From: znek Date: Fri, 20 Aug 2004 10:08:27 +0000 (+0000) Subject: initial import of CVS snapshot 2004-08-20 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22f5b86f2193c87cffef116159af2ba4660e4627;p=sope initial import of CVS snapshot 2004-08-20 git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- 22f5b86f2193c87cffef116159af2ba4660e4627 diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000..c928419b --- /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 index 00000000..c684af40 --- /dev/null +++ b/GNUmakefile @@ -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 index 00000000..ab0c70ac --- /dev/null +++ b/PROJECTLEAD @@ -0,0 +1,3 @@ +# $Id$ + +PROJECTLEAD=helge.hess@opengroupware.org diff --git a/README b/README new file mode 100644 index 00000000..f9b569d8 --- /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 index 00000000..ef15de76 --- /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 index 00000000..e89ac988 --- /dev/null +++ b/mod_ngobjweb/.cvsignore @@ -0,0 +1 @@ +core.* diff --git a/mod_ngobjweb/CHANGES b/mod_ngobjweb/CHANGES new file mode 100644 index 00000000..89893e1b --- /dev/null +++ b/mod_ngobjweb/CHANGES @@ -0,0 +1,16 @@ +Fri Jan 31 13:04:03 CET 2003 Helge Hess +------------------------------------------------------------- + +- fixed a small bug in the configuration of SNSAppPrefix + => not used in SkyrixGreen + +------------------------------------------------------------- +Tue Dec 10 12:33:00 CET 2002 Helge Hess + +- created CHANGES file to document changes on a higher level + +------------------------------------------------------------- +Tue Jul 2 16:09:56 2002 Jan Reichmann + +- 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 index 00000000..c928419b --- /dev/null +++ b/mod_ngobjweb/COPYRIGHT @@ -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 index 00000000..62971b8a --- /dev/null +++ b/mod_ngobjweb/ChangeLog @@ -0,0 +1,75 @@ +2004-04-02 Marcus Mueller + + * README: Minor additions/changes for Apache 1.3.x + +2003-12-22 Frank Reppin + + * 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 + for pointing! + +2003-08-08 Helge Hess + + * 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 + + * globals.c, common.h: added some missing headers to remove compilation + warnings on FreeBSD RELENG_4 (thanks to Frank Reppin ) + +2003-07-15 Thomas Woerner + + * port to apache 2.x + + * thanks to Ricardo Cerqueira for testing + +2003-02-05 Helge Hess + + * globals.c: disable HEAVY_LOG per default + +2003-01-31 Helge Hess + + * config.c: fixed a bug in the configuration of SNSAppPrefix + +2002-12-10 Helge Hess + + * added CHANGES + +Tue Jul 2 16:09:56 2002 Jan Reichmann + + * 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 + + * removed "global" sns config (you need to specify the sns + explicitly using SetSNSPort + + * handler.c: major cleanups + +2001-11-12 Helge Hess + + * sns.c (_sendSNSQuery): added fail-codes + +Tue Oct 9 15:42:07 2001 Helge Hess + + * sns.c: removed support for SNS over HTTP + +Wed Feb 28 16:03:14 2001 Helge Hess + + * sns.c (_sendSNSQuery): fixed bugs in HTTP support + +Fri Dec 1 16:08:00 2000 Helge Hess + + * added apxs support + +Tue Aug 3 16:35:38 1999 Helge Hess + + * 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 index 00000000..4f7cb840 --- /dev/null +++ b/mod_ngobjweb/GNUmakefile @@ -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 index 00000000..620ae404 --- /dev/null +++ b/mod_ngobjweb/NGBufferedDescriptor.c @@ -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 +#include +#include +#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 index 00000000..9e489f89 --- /dev/null +++ b/mod_ngobjweb/NGBufferedDescriptor.h @@ -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 index 00000000..d33984ca --- /dev/null +++ b/mod_ngobjweb/README @@ -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 +--------------------- + +SetHandler ngobjweb-adaptor +SetAppPort 20000 + + +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 index 00000000..037ffd7b --- /dev/null +++ b/mod_ngobjweb/apversion.sh @@ -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 index 00000000..9640e096 --- /dev/null +++ b/mod_ngobjweb/common.h @@ -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 +#include +#include +#include +#include +#include +#include + +/* Apache includes */ + +#include +#include +#include +#include +#include + +#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 index 00000000..6184c045 --- /dev/null +++ b/mod_ngobjweb/config.c @@ -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 index 00000000..00357b89 --- /dev/null +++ b/mod_ngobjweb/globals.c @@ -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 +#include + +int HEAVY_LOG = 0; +//struct sockaddr *sns = 0; diff --git a/mod_ngobjweb/handler.c b/mod_ngobjweb/handler.c new file mode 100644 index 00000000..e9061510 --- /dev/null +++ b/mod_ngobjweb/handler.c @@ -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 index 00000000..c04f1529 --- /dev/null +++ b/mod_ngobjweb/httpd.conf @@ -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 ); +# 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 +# definition. These values also provide defaults for +# any containers you may define later in the file. +# +# All of these directives may appear inside 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. +# + + Options FollowSymLinks + AllowOverride None + + +# +# 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. +# + + +# +# 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 + + +# +# 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 +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# 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 +# container, they will be logged here. Contrariwise, if you *do* +# define per- 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. +# + + SetHandler server-status + Order deny,allow + Deny from all + Allow from localhost + + +# +# 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. +# +# +# SetHandler server-info +# Order deny,allow +# Deny from all +# Allow from .your_domain.com +# diff --git a/mod_ngobjweb/ngobjweb_module.c b/mod_ngobjweb/ngobjweb_module.c new file mode 100644 index 00000000..84291e49 --- /dev/null +++ b/mod_ngobjweb/ngobjweb_module.c @@ -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 index 00000000..8ff7928b --- /dev/null +++ b/mod_ngobjweb/scanhttp.c @@ -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 index 00000000..a8cd0c86 --- /dev/null +++ b/mod_ngobjweb/skyrix.conf @@ -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 + + +SetSNSPort /tmp/.helge.snsd +SetHandler ngobjweb-adaptor + + + +SetSNSPort /tmp/.helge.snsd +SetAppPrefix /OtherRoot +SetHandler ngobjweb-adaptor + + + +SetSNSPort /tmp/.helge.snsd2 +SetAppPrefix /OtherRoot2 +SetHandler ngobjweb-adaptor + + + +SetSNSPort /tmp/.helge.snsd +SetHandler ngobjweb-adaptor + + + +SetHandler ngobjweb-adaptor + + + +SetHandler ngobjweb-adaptor + + + +SetHandler ngobjweb-adaptor + diff --git a/mod_ngobjweb/sns.c b/mod_ngobjweb/sns.c new file mode 100644 index 00000000..4b7e967b --- /dev/null +++ b/mod_ngobjweb/sns.c @@ -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 index 00000000..2bc8c170 --- /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 index 00000000..8d4bfcfd --- /dev/null +++ b/skyrix-core/.cvsignore @@ -0,0 +1 @@ +nohup.out diff --git a/skyrix-core/COPYING b/skyrix-core/COPYING new file mode 100644 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..8e764497 --- /dev/null +++ b/skyrix-core/COPYRIGHT @@ -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 index 00000000..da099286 --- /dev/null +++ b/skyrix-core/ChangeLog @@ -0,0 +1,64 @@ +2004-08-16 Marcus Mueller + + * SxCore.xcode: added NGCalendarDateRange.[hm] + +2004-07-21 Marcus Mueller + + * SxCore.xcode: fixed incorrect framework search paths. + +2004-07-21 Marcus Mueller + + * README-OSX.txt: Major overhaul for build description, especially the + Xcode section. + +2004-07-16 Marcus Mueller + + * 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 + + * SxCore.xcode: removed NGCString from NGExtensions (deprecated) + +2004-06-09 Helge Hess + + * 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 + + * SxCore.xcode: added subclassing test tool + +2004-03-24 Marcus Mueller + + * SxCore.xcode: added NSString+German.[hm] in NGExtensions. + Also, added -headerpad_max_install_names link option where + appropriate. + +2004-03-15 Helge Hess + + * SxCore.xcode: added new plist categories in NGExtensions to Xcode + project + +2004-03-08 Helge Hess + + * SxCore.xcode: added new source files in EOControl to Xcode project + + * README-OSX.txt: added some build notes + +2004-02-10 Marcus Mueller + + * 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 index 00000000..49a10b1a --- /dev/null +++ b/skyrix-core/EOControl/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/EOControl/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-core/EOControl/COPYRIGHT @@ -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 index 00000000..1531b667 --- /dev/null +++ b/skyrix-core/EOControl/ChangeLog @@ -0,0 +1,127 @@ +2004-07-22 Helge Hess + + * EOKeyComparisonQualifier.m, EOKeyValueQualifier.m, + EOKeyValueArchiver.m, EOFetchSpecification.m: fixed gcc 3.4 warnings + (v4.2.46) + +2004-06-09 Helge Hess + + * v4.2.45 + + * GNUmakefile.preamble: added prebinding + + * GNUmakefile: minor cleanups + +2004-05-16 Helge Hess + + * EOKeyComparisonQualifier.m, EOKeyValueQualifier.m, EOQualifier.m, + EOQualifierVariable.m: minor code cleanups, fixed some "== YES" + comparisons (v4.2.44) + +2004-04-07 Helge Hess + + * EOQualifierParser.m: minor code cleanups (==YES) (v4.2.43) + +2004-03-15 Helge Hess + + * EOFetchSpecification, EOQualifier, EOSortOrdering: moved property + list initializer methods to NGExtensions to improve GDL2 + compatibility (v4.2.42) + +2004-03-11 Helge Hess + + * EOFetchSpecification, EOQualifier, EOSortOrdering: deprecated + -initWithPropertyList: method, added new -initWithPropertyList:owner: + method (like in EOPropertyListEncoding) (v4.2.41) + +2004-03-09 Helge Hess + + * EOFetchSpecification.m: subminor improvement in -copyWithZone: + method (v4.2.40) + +2004-03-03 Helge Hess + + * EOFetchSpecification.m: fixed a recursion introduced in v4.2.38 + (v4.2.39) + +2004-03-02 Helge Hess + + * 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 + + * EOKeyValueCoding.m: do not invoke NSDictionary -objectForKey: with + 'nil' key (v4.2.37) + +2003-11-25 Helge Hess + + * removed unused source files (v4.2.36) [what was v4.2.35?, missing] + +2003-11-14 Helge Hess + + * EOSortOrdering.m: added an assertion to prevent index overflows + (v4.2.34) + +Tue Nov 11 12:01:10 2003 Jan Reichmann + + * common.h: fixed Free marcro declaration (introduced in 4.2.33) + (v4.2.34) + +2003-11-09 Helge Hess + + * 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 + + * 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 + + * EOFault.m/EOFaultHandler.m: ported to NeXT runtime (v4.2.30) + +2003-09-01 Helge Hess + + * changed not to require FoundationExt on MacOSX (v4.2.29) + +2003-08-07 Helge Hess + + * 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 + + * added to OpenGroupware.org + + * stripped out old ChangeLogs, unimportant for OGo + +Wed Dec 8 18:35:40 1999 Helge Hess + + * created ChangeLog diff --git a/skyrix-core/EOControl/EOAndQualifier.m b/skyrix-core/EOControl/EOAndQualifier.m new file mode 100644 index 00000000..86b8974e --- /dev/null +++ b/skyrix-core/EOControl/EOAndQualifier.m @@ -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 +#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 index 00000000..6054b264 --- /dev/null +++ b/skyrix-core/EOControl/EOArrayDataSource.h @@ -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 + +@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 index 00000000..645b4633 --- /dev/null +++ b/skyrix-core/EOControl/EOArrayDataSource.m @@ -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 +#include +#include +#include +#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 index 00000000..6617cb30 --- /dev/null +++ b/skyrix-core/EOControl/EOClassDescription.h @@ -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 +#include + +@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 index 00000000..a76db6b7 --- /dev/null +++ b/skyrix-core/EOControl/EOClassDescription.m @@ -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 index 00000000..c84c03f0 --- /dev/null +++ b/skyrix-core/EOControl/EOControl-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + EOControl + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.EOControl + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/EOControl/EOControl.h b/skyrix-core/EOControl/EOControl.h new file mode 100644 index 00000000..3918a802 --- /dev/null +++ b/skyrix-core/EOControl/EOControl.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __EOControl_H__ */ diff --git a/skyrix-core/EOControl/EOControlDecls.h b/skyrix-core/EOControl/EOControlDecls.h new file mode 100644 index 00000000..fcb28cb0 --- /dev/null +++ b/skyrix-core/EOControl/EOControlDecls.h @@ -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 index 00000000..a8e4b543 --- /dev/null +++ b/skyrix-core/EOControl/EODataSource.h @@ -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 + +@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 index 00000000..fc50672c --- /dev/null +++ b/skyrix-core/EOControl/EODataSource.m @@ -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 +#include +#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 index 00000000..d0c95236 --- /dev/null +++ b/skyrix-core/EOControl/EODetailDataSource.h @@ -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 + +@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 index 00000000..05415593 --- /dev/null +++ b/skyrix-core/EOControl/EODetailDataSource.m @@ -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 +#include +#include +#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 index 00000000..b25efe5b --- /dev/null +++ b/skyrix-core/EOControl/EOFetchSpecification.h @@ -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 + +@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 index 00000000..870ef93d --- /dev/null +++ b/skyrix-core/EOControl/EOFetchSpecification.m @@ -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 index 00000000..8baf4431 --- /dev/null +++ b/skyrix-core/EOControl/EOGenericRecord.h @@ -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 +#import +#include + +@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 index 00000000..53b49754 --- /dev/null +++ b/skyrix-core/EOControl/EOGenericRecord.m @@ -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 + +@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 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 "); + + 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: + @"", + [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 index 00000000..e66a2d0f --- /dev/null +++ b/skyrix-core/EOControl/EOGlobalID.h @@ -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 + +@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 index 00000000..ae567d0c --- /dev/null +++ b/skyrix-core/EOControl/EOGlobalID.m @@ -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 +#include +#if !defined(__MINGW32__) +# include +#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 index 00000000..23ff8949 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyComparisonQualifier.m @@ -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 +#include +#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 index 00000000..88fdd353 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyGlobalID.h @@ -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 + +@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 index 00000000..5e7ea9d8 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyGlobalID.m @@ -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 index 00000000..652d8447 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyValueArchiver.h @@ -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 + +@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 index 00000000..cc076fbb --- /dev/null +++ b/skyrix-core/EOControl/EOKeyValueArchiver.m @@ -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 index 00000000..8b4a9028 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyValueCoding.h @@ -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 +#import + +#if NeXT_Foundation_LIBRARY + +#import + +#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 index 00000000..7cc47a07 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyValueCoding.m @@ -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 +# include +#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 index 00000000..35ee01e3 --- /dev/null +++ b/skyrix-core/EOControl/EOKeyValueQualifier.m @@ -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 +#include +#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 index 00000000..5ec16fd7 --- /dev/null +++ b/skyrix-core/EOControl/EONotQualifier.m @@ -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 +#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 index 00000000..731e42a3 --- /dev/null +++ b/skyrix-core/EOControl/EONull.h @@ -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 + +#ifndef HAVE_NSNull +# define HAVE_NSNull 1 +#endif + +#if HAVE_NSNull + +#import + +#define EONull NSNull + +#else /* !HAVE_NSNull | NeXT Foundation */ + +#import + +@interface EONull : NSObject + ++ (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 index 00000000..fae02849 --- /dev/null +++ b/skyrix-core/EOControl/EONull.m @@ -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 index 00000000..ae158bfc --- /dev/null +++ b/skyrix-core/EOControl/EOObserver.h @@ -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 + +@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)_observer forObject:(id)_object; ++ (void)removeObserver:(id)_observer forObject:(id)_object; ++ (void)addOmniscientObserver:(id)_observer; ++ (void)removeOmniscientObserver:(id)_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 index 00000000..b74769f8 --- /dev/null +++ b/skyrix-core/EOControl/EOObserver.m @@ -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 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)_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)_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)_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)_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 index 00000000..89e51176 --- /dev/null +++ b/skyrix-core/EOControl/EOOrQualifier.m @@ -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 +#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 index 00000000..f40313e9 --- /dev/null +++ b/skyrix-core/EOControl/EOQualifier.h @@ -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 + +/* + 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 + +@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 index 00000000..8874bcdc --- /dev/null +++ b/skyrix-core/EOControl/EOQualifier.m @@ -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 +#include "EOQualifier.h" +#include "EOKeyValueCoding.h" +#include "common.h" +#include "EONull.h" +#import + +@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)self evaluateWithObject:_object]; +} + +@end /* EOQualifier(QuickEval) */ diff --git a/skyrix-core/EOControl/EOQualifierParser.m b/skyrix-core/EOControl/EOQualifierParser.m new file mode 100644 index 00000000..25a84aa4 --- /dev/null +++ b/skyrix-core/EOControl/EOQualifierParser.m @@ -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 +#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:@"", _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 index 00000000..72642477 --- /dev/null +++ b/skyrix-core/EOControl/EOQualifierVariable.m @@ -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 index 00000000..a527b86b --- /dev/null +++ b/skyrix-core/EOControl/EOSQLParser.h @@ -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 +#import + +/* + 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 index 00000000..2d8b7a6b --- /dev/null +++ b/skyrix-core/EOControl/EOSQLParser.m @@ -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 index 00000000..7e16889a --- /dev/null +++ b/skyrix-core/EOControl/EOSortOrdering.h @@ -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 +#include + +@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 + +@interface NSArray(EOSortOrdering) + +- (NSArray *)sortedArrayUsingKeyOrderArray:(NSArray *)_orderings; + +@end + +@interface NSMutableArray(EOSortOrdering) + +- (void)sortUsingKeyOrderArray:(NSArray *)_orderings; + +@end + +#import + +@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 index 00000000..5bb9baa4 --- /dev/null +++ b/skyrix-core/EOControl/EOSortOrdering.m @@ -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 +#include "common.h" + +#if GNU_RUNTIME +# include +#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 index 00000000..2a39d91b --- /dev/null +++ b/skyrix-core/EOControl/EOValidation.m @@ -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 index 00000000..0fd72a3f --- /dev/null +++ b/skyrix-core/EOControl/GNUmakefile @@ -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 index 00000000..b9697167 --- /dev/null +++ b/skyrix-core/EOControl/GNUmakefile.preamble @@ -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 index 00000000..7414293d --- /dev/null +++ b/skyrix-core/EOControl/NSArray+EOQualifier.m @@ -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 +#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)_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 index 00000000..cea67032 --- /dev/null +++ b/skyrix-core/EOControl/NSObject+EOQualifierOps.m @@ -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 index 00000000..3f5b726a --- /dev/null +++ b/skyrix-core/EOControl/NSObject+QualDesc.m @@ -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 index 00000000..8b577a47 --- /dev/null +++ b/skyrix-core/EOControl/README @@ -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 index 00000000..d3f49573 --- /dev/null +++ b/skyrix-core/EOControl/SxCore-EOControl.graffle @@ -0,0 +1,1474 @@ + + + + + CanvasColor + + w + 1.000000e+00 + + ColumnAlign + 0 + ColumnSpacing + 5.400000e+01 + GraphDocumentVersion + 2 + GraphicsList + + + Bounds + {{45, 414}, {162, 18}} + Class + ShapedGraphic + ID + 2788 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 351}, {162, 18}} + Class + ShapedGraphic + ID + 2787 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGenericRecord.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{243, 270}, {135, 18}} + Class + ShapedGraphic + ID + 2782 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyGlobalID.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{387, 270}, {135, 18}} + Class + ShapedGraphic + ID + 2783 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGlobalID.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{315, 234}, {135, 18}} + Class + ShapedGraphic + ID + 2784 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOGlobalID.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 2782 + + ID + 2785 + Points + + {364.5, 252} + {328.5, 270} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2784 + + + + Class + LineGraphic + Head + + ID + 2783 + + ID + 2786 + Points + + {400.5, 252} + {436.5, 270} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2784 + + + + ID + 2781 + + + Bounds + {{45, 315}, {162, 18}} + Class + ShapedGraphic + ID + 2780 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOSortOrdering.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 162}, {162, 18}} + Class + ShapedGraphic + ID + 2779 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{99, 585}, {126, 18}} + Class + ShapedGraphic + ID + 2762 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{297, 630}, {126, 18}} + Class + ShapedGraphic + ID + 2763 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{315, 594}, {126, 18}} + Class + ShapedGraphic + ID + 2764 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{333, 558}, {126, 18}} + Class + ShapedGraphic + ID + 2765 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 504}, {135, 18}} + Class + ShapedGraphic + ID + 2766 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{279, 504}, {126, 18}} + Class + ShapedGraphic + ID + 2767 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 630}, {171, 18}} + Class + ShapedGraphic + ID + 2768 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOQualifier.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 2762 + + ID + 2769 + Points + + {166, 522} + {162.5, 585} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2766 + + + + Class + LineGraphic + Head + + ID + 2762 + + ID + 2770 + Points + + {322, 522} + {182, 585} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2767 + + + + Class + LineGraphic + Head + + ID + 2763 + + ID + 2771 + Points + + {180.321, 522} + {346.179, 630} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2766 + + + + Class + LineGraphic + Head + + ID + 2763 + + ID + 2772 + Points + + {343.286, 522} + {358.714, 630} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2767 + + + + Class + LineGraphic + Head + + ID + 2764 + + ID + 2773 + Points + + {187.65, 522} + {356.85, 594} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2766 + + + + Class + LineGraphic + Head + + ID + 2764 + + ID + 2774 + Points + + {345.6, 522} + {374.4, 594} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2767 + + + + Class + LineGraphic + Head + + ID + 2765 + + ID + 2775 + Points + + {204.75, 522} + {357.75, 558} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2766 + + + + Class + LineGraphic + Head + + ID + 2765 + + ID + 2776 + Points + + {351, 522} + {387, 558} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2767 + + + + Class + LineGraphic + Head + + ID + 2768 + + ID + 2777 + Points + + {167.786, 522} + {183.214, 630} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2766 + + + + Class + LineGraphic + Head + + ID + 2768 + + ID + 2778 + Points + + {330.75, 522} + {195.75, 630} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2767 + + + + ID + 2761 + + + Class + Group + Graphics + + + Bounds + {{243, 342}, {126, 18}} + Class + ShapedGraphic + ID + 2759 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{243, 378}, {126, 18}} + Class + ShapedGraphic + ID + 2760 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOClassDescription.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 2758 + + + Class + Group + Graphics + + + Bounds + {{387, 342}, {126, 18}} + Class + ShapedGraphic + ID + 2755 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{387, 378}, {126, 18}} + Class + ShapedGraphic + ID + 2756 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{387, 414}, {126, 18}} + Class + ShapedGraphic + ID + 2757 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 2754 + + + Class + Group + Graphics + + + Bounds + {{252, 153}, {126, 18}} + Class + ShapedGraphic + ID + 2749 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODetailDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{387, 153}, {126, 18}} + Class + ShapedGraphic + ID + 2750 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOArrayDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{324, 117}, {126, 18}} + Class + ShapedGraphic + ID + 2751 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 2749 + + ID + 2752 + Points + + {369, 135} + {333, 153} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2751 + + + + Class + LineGraphic + Head + + ID + 2750 + + ID + 2753 + Points + + {402.75, 135} + {434.25, 153} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2751 + + + + ID + 2748 + + + Bounds + {{45, 126}, {162, 18}} + Class + ShapedGraphic + ID + 2747 + Link + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc + +\f0\fs24 \cf0 } + + + + Bounds + {{45, 99}, {162, 18}} + Class + ShapedGraphic + ID + 2746 + Link + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc + +\f0\fs24 \cf0 } + + + + Bounds + {{45, 288}, {162, 18}} + Class + ShapedGraphic + ID + 2745 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOFetchSpecification.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 189}, {162, 18}} + Class + ShapedGraphic + ID + 2744 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOObserver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 378}, {162, 18}} + Class + ShapedGraphic + ID + 2743 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EONull.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 252}, {162, 18}} + Class + ShapedGraphic + ID + 2742 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyValueArchiver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 225}, {162, 18}} + Class + ShapedGraphic + ID + 2741 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EOKeyValueArchiver.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 2760 + + ID + 2740 + Points + + {306, 360} + {306, 378} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2759 + + + + Class + LineGraphic + Head + + ID + 2756 + + ID + 2739 + Points + + {450, 360} + {450, 378} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2755 + + + + Class + LineGraphic + Head + + ID + 2757 + + ID + 2738 + Points + + {450, 396} + {450, 414} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2756 + + + + GridInfo + + HPages + 1 + ImageCounter + 1 + IsPalette + NO + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + AutoAdjust + YES + HierarchicalOrientation + 0 + MagneticFieldCenter + {0, 0} + + MagnetsEnabled + YES + PageBreakColor + + w + 3.333333e-01 + + PageBreaks + YES + PageSetup + + BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE + hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT + dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE + mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm + nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl + c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp + ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL + TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk + ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv + bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE + mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4AhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh + dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp + boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT + aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQJkgQMYhoaG + + RowAlign + 0 + RowSpacing + 8.999991e+00 + VPages + 1 + WindowInfo + + Frame + {{67, 21}, {821, 897}} + VisibleRegion + {{-133, -50}, {806, 820}} + Zoom + 1 + + + diff --git a/skyrix-core/EOControl/TODO b/skyrix-core/EOControl/TODO new file mode 100644 index 00000000..8de3631b --- /dev/null +++ b/skyrix-core/EOControl/TODO @@ -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 index 00000000..5cae3ac1 --- /dev/null +++ b/skyrix-core/EOControl/Version @@ -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 index 00000000..69c3bb48 --- /dev/null +++ b/skyrix-core/EOControl/common.h @@ -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 +#include + +#import +#import + +#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 index 00000000..5180d590 --- /dev/null +++ b/skyrix-core/EOControl/libEOControl.def @@ -0,0 +1,5 @@ +EXPORTS + EOCompareAscending; + EOCompareDescending; + EOCompareCaseInsensitiveAscending; + EOCompareCaseInsensitiveDescending; diff --git a/skyrix-core/GNUmakefile b/skyrix-core/GNUmakefile new file mode 100644 index 00000000..2de42883 --- /dev/null +++ b/skyrix-core/GNUmakefile @@ -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 index 00000000..53fe1e1f --- /dev/null +++ b/skyrix-core/NGExtensions/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGExtensions/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-core/NGExtensions/COPYRIGHT @@ -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 index 00000000..8496314f --- /dev/null +++ b/skyrix-core/NGExtensions/ChangeLog @@ -0,0 +1,1114 @@ +2004-08-16 Helge Hess + + * NGCalendarDateRange.m: added range category on NSArray, added some + methods to daterange (v4.2.102) + +2004-08-16 Marcus Mueller + + * added NGCalendarDateRange class (v4.2.101) + +2004-07-26 Helge Hess + + * 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 + + * EOExt.subproj/EOKeyMapDataSource.m: fixed a gcc 3.4 warning (v4.2.99) + +2004-07-14 Helge Hess + + * FdExt.subproj/NSString+Encoding.m: improved error logs in case an + iconv buffer is too small (v4.2.98) + +2004-06-27 Helge Hess + + * NGExtensions/FdExt.subproj/NGPropertyListParser.m: minor cleanups to + log messages (v4.2.97) + +2004-06-22 Helge Hess + + * 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 + + * 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 + + * 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 + + * NGExtensions/GNUmakefile.preamble: added prebinding (v4.2.92) + +2004-06-08 Helge Hess + + * 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 + + * NGExtensions/NSString+misc.[hm]: improved, now works with any object + which supports KVC (v4.2.89) + +2004-06-07 Helge Hess + + * NGBundleManager.m: fixed gcc 3.4 warnings (v4.2.88) + +2004-06-05 Stephane Corthesy + + * NGBundleManager.m(-bundleForClass:): added basic support for classes + defined in frameworks (v4.2.87) + +2004-06-03 Helge Hess + + * NGObjCRuntime.m: added a hack to make NGObjCRuntime.m compile with + gcc 3.4.0 (v4.2.86) + +2004-06-01 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * 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 + + * EOExt.subproj/EOSortOrdering+plist.m: fixed wrong mappings for + case insensitive sortOrderings (v4.2.80) + +2004-05-01 Marcus Mueller + + * 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 + + * NGObjCRuntime.m: improved support for Apple runtime (v4.2.78) + +2004-04-07 Jean-Alexis Montignies + + * NGHashMap: added because used in NGObjWeb + -asDictionaryWithArraysForValues (v4.2.77) + +2004-04-07 Helge Hess + + * NGExtensions/NSString+Encoding.h: exported + +stringEncodingForEncodingNamed: on Cocoa (v4.2.76) + +2004-04-01 Helge Hess + + * 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 + + * 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 + + * 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 + + * EOExt: moved in property list initializer methods from EOControl (to + make them available for GDL2) + +2004-03-14 Helge Hess + + * 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 + + * EOFilterDataSource: code cleanups, added -description method + (v4.2.70) + +2004-03-11 Helge Hess + + * NGBundleManager.m: disabled a debug log (v4.2.69) + +2004-03-10 Donald Duck + + * NGBundleManager.m: print a warning if the NGBundlePath default is not + configured (v4.2.68) + +2004-03-08 Helge Hess + + * FdExt.subproj/NSException+misc.m: added a -copyWithZone: method, + as used by the XML-RPC client (v4.2.67) + +2004-03-01 Helge Hess + + * 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 + + * FdExt.subproj/NSNull+misc.m: added -descriptionWithLocale: on MacOSX + (v4.2.65) + +2004-02-23 Helge Hess + + * 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 + + * 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 + + * 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 + + * NGBundleManager.m: disabled class-hook debugging on OSX (v4.2.61) + +2004-02-10 Helge Hess + + * NGStack.m: fixed minor compilation warning on OSX (v4.2.60) + +2004-02-08 Helge Hess + + * 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 + + * FdExt.subproj/NSFileManager+Extensions.m: renamed category to + ExtendedFileManagerImp to avoid gcc warnings (v4.2.58) + +2003-12-28 Helge Hess + + * NGBundleManager.m: minor cleanups (v4.2.57) + +2003-11-30 Helge Hess + + * 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 + + * 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 + + * FdExt.subproj/NSString+Formatting.m: minor speed and MacOSX + compatibility improvements (v4.2.53) + +2003-10-27 Helge Hess + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGBundleManager.m: cache bundle using name.extension instead of name + only (v4.2.38) + +2003-06-23 Helge Hess + + * NGFileManager.m: ignore empty strings during path standardization + (reason for publisher bug 1778) (v4.2.37) + +2003-06-06 Jan Reichmann + + * NSString+Encoding.m: added a category to encode/decode string from + arbitary encoding formats using libiconv (v4.2.36) + +2003-05-26 Helge Hess + + * updated MacOSX port, some smaller modification to compile without + FoundationExt (exceptions, memory allocation, plist parsing) + (v4.2.35) + +2003-05-19 Helge Hess + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGObjCRuntime.m: added a hack for GNUstep Base with the incomplete + FoundationExt library (v4.2.23) + +2003-04-01 Helge Hess + + * added compilation support for GNUstep base (v4.2.22) + +2003-03-14 Helge Hess + + * NSString+misc.m: do not encode umlaut entities in XML output + (v4.2.21) + +2003-03-09 Helge Hess + + * NGBase64Coding.m: added -stringByEncodingBase64 and + -stringByDecodingBase64 to NSData (v4.2.20) + +Tue Mar 4 13:53:40 2003 Jan Reichmann + + * 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 + + * 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 + + * NSCalendarDate+misc.m + ([NSCalendarDate -dateByAddingYears:months:days:]): + fixed month overflow (bug 871) (v4.2.17) + +2003-01-10 Helge Hess + + * 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 + + * 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 + + * fixed Copyright headers in most files (v4.2.14) + +Mon Dec 23 15:34:51 2002 Helge Hess + + * 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 + + * NSString+misc.m: added some methods for processing fully qualified + XML names (v4.2.12) + +2002-11-22 Helge Hess + + * EOKeyMapDataSource.m: finished EOKeyMapDataSource (v4.2.11) + + * EOKeyMapDataSource.m: started EOKeyMapDataSource (v4.2.10) + + * EOCacheDataSource.m: tiny code cleanups + +2002-11-15 Helge Hess + + * NSURL+misc.m: fixed an index bug in URL string processing (v4.2.9) + +2002-10-30 Helge Hess + + * NSDictionary+misc: added a method + -dictionaryByExchangingKeysAndValues to reverse the mapping of a + dictionary (v4.2.8) + +2002-10-21 Helge Hess + + * NGStringScanEnumerator.m: properly clear data when being passed an + empty NSData (v4.2.7) + +Thu Oct 17 16:18:49 2002 Helge Hess + + * 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 + + * NSEnumerator+misc.m, NSProcessInfo+misc.m: removed some compilation + warnings (v4.2.5) + +Fri Aug 30 11:40:59 2002 Jan Reichmann + + * NGQuotedPrintableCoding.m: (Suse Bug 18600) fixed + 'Soft line Breaks'-Bug (v4.2.4) + +2002-08-15 Helge Hess + + * NSFileManager+Extensions.m: added support for GlobalIDs, make + relative pathes absolute before calling standarizePath (v4.2.3) + +2002-07-12 Helge Hess + + * moved tools/tests to skyrix-core/samples + +2002-05-31 Helge Hess + + * NGBundleManager.m: changed to work with gstep-base library + +2002-05-23 Helge Hess + + * moved from Skyrix-dev-42 repository to skyrix-core (v4.2.2) + +Fri May 17 14:51:13 2002 Helge Hess + + * added NSData+gzip category from NGZlib + +Thu May 2 15:21:00 2002 Helge Hess + + * added NSURL+misc for handling relative NSURLs + +Thu May 2 13:38:11 2002 Helge Hess + + * made some modifications to support gstep-base + +Mon Apr 29 11:35:31 2002 Helge Hess + + * NSProcessInfo+misc.m: added convenience methods: + -argumentsWithoutDefaults + +Tue Apr 16 13:13:05 2002 Helge Hess + + * NSString+misc.m: fixed bug with HTML escaping \n \r etc + +Tue Feb 12 21:04:16 2002 Helge Hess + + * NSObject+Values.m: the -stringValue of NSMutableString now returns an + immutable copy + + * added DOM extensions + +Sat Feb 9 12:25:57 2002 Helge Hess + + * added object logging methods + +Wed Feb 6 11:54:04 2002 Helge Hess + + * NSProcessInfo+misc.m: added -temporaryFileName + +Mon Jan 7 15:33:41 2002 Helge Hess + + * NGBundleManager.m: use a set for resource lookup to avoid duplicates + +Mon Dec 17 15:19:23 2001 Helge Hess + + * NGFileManager.m: added -trashFileAtPath:handler: method + +Tue Nov 27 19:30:29 2001 Helge Hess + + * NGBundleManager: made NGBundle class public + + * NSProcessInfo+misc.m: speed optimized /proc processing ... + +Thu Nov 22 10:48:29 2001 Helge Hess + + * NSCalendarDate+misc.m: added method for calculation of + easter + +Tue Nov 6 12:06:49 2001 Helge Hess + + * removed NGFileManager*Tools from Sascha, too many dependencies on + SkyProject ... + +Tue Nov 6 12:00:11 2001 Helge Hess + + * added NGFileManager*Tools from Sascha + +Thu Oct 18 15:34:13 2001 Helge Hess + + * NSNull+misc.m: added forwarding code to catch unknown selectors + +Tue Oct 16 16:34:25 2001 Helge Hess + + * 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 + + * NSNull+misc.m: implemented KVC for NSNull ... + +Mon Oct 15 15:33:52 2001 Helge Hess + + * 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 + + * 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 + + * 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 + + * added NSProcessInfo+misc for querying the /proc filesystem + +Fri Aug 10 13:31:28 2001 Helge Hess + + * added NGFileManager class + +Thu Aug 9 13:49:30 2001 Helge Hess + + * NSString+misc.m (NGUnescapeUrlBuffer): added URL escaping/unescaping + +Tue Jul 31 11:27:46 2001 Martin Spindler + + * EOFilterDataSource.m: can handle groupings now + +Tue Jul 10 11:56:18 2001 Helge Hess + + * NSCalendarDate+misc.m(firstMondayAndLastWeekInYear:): do not dump + core if passed NULL + +2001-06-26 Helge Hess + + * removed NGNil, NGArchiver + + * moved to SkyDev41 + +Wed May 30 14:47:11 2001 Helge Hess + + * EOFilterDataSource.m: completed + +Thu May 10 11:23:57 2001 Helge Hess + + * NGBundleManager.m: improved error handling + +Mon Apr 30 10:44:02 2001 Helge Hess + + * EOCacheDataSource.m: added -description + +Thu Apr 19 11:58:57 2001 Jan Reichmann + + * EOCompoundDataSource.m: insert mh bugfix (return empty array instead + of nil); fixed sources notification bug + +Tue Apr 10 13:15:38 2001 Helge Hess + + * NGFileManager.h: completed NGFileManager protocol + +Mon Mar 26 12:29:14 2001 Helge Hess + + * added NSNull+misc with -isNotNull + +Thu Mar 8 16:51:31 2001 Helge Hess + + * EOKeyGrouping.m: fixed bug with 'nil' in -addObject: + +Tue Feb 13 10:51:03 2001 Helge Hess + + * EOGrouping.m: added -setGroupings/-groupings to EOFetchSpecification + +Tue Feb 13 10:31:29 2001 Helge Hess + + * fixed bugs in grouping stuff + +Tue Feb 6 18:18:48 2001 Martin Spindler + + * NSArray+Grouping.[hm], EO*Grouping.[hm]: added + +Mon Jan 29 15:36:07 2001 Helge Hess + + * NSFileManager+Extensions.m: added trash-folder support + +Wed Jan 24 19:35:43 2001 Jan Reichmann + + * NSString+misc.[mh]: add FilePathVersioningMethods + +Wed Jan 24 19:35:00 2001 Jan Reichmann + + * NSFileManager+Extensions.h: add fileAttributesAtPath:traverseLink: + version: + +Tue Jan 23 18:04:35 2001 Helge Hess + + * EOQualifier+CtxEval.m: fixed bug in parameter countin + +Thu Jan 18 17:04:07 2001 Helge Hess + + * NSFileManager+Extensions: changed feature-check methods + +Tue Jan 16 11:28:38 2001 Jan Reichmann + + * EOCacheDataSource.m: fixed timeout bug + +Mon Jan 15 14:24:45 2001 Helge Hess + + * NSFileManager+Extensions.h: added locking protocol + +Mon Jan 15 12:54:54 2001 Helge Hess + + * NSFileManager+Extensions.h: added methods for versioning + +Sun Jan 14 19:27:23 2001 Jan Reichmann + + * EOCacheDataSource.[mh]: improved timeout + +Fri Jan 12 18:29:33 2001 Jan Reichmann + + * EOCacheDataSource.[hm]: timeout + +Wed Jan 10 15:56:40 2001 Helge Hess + + * EODataSource+NGExtensions.m: added EONoFetchWithEmptyQualifierHint + +Wed Jan 3 15:36:40 2001 Jan Reichmann + + * EOCacheDataSource.m: fixed dealloc bug + +Thu Oct 26 20:00:41 2000 Jan Reichmann + + * EOQualifier+CtxEval.m: fixed log bug + +Thu Oct 19 14:31:48 2000 Helge Hess + + * NSString+misc.m: added changes of Jan + +Mon Oct 16 19:30:30 2000 Martin Spindler + + * EODataSource+NGExtensions.m: added + +Mon Oct 2 18:04:28 2000 Helge Hess + + * NSString+Formatting.m: added %ll specifier for long-long types + +Thu Aug 31 17:54:59 2000 Helge Hess + + * NSEnumerator+misc: added this new category/classes + +Fri Aug 18 15:09:14 2000 Helge Hess + + * NGBundleManager.m: cache bundle manager object + +Thu Aug 17 13:43:06 2000 Helge Hess + + * NGBundleManager.m: always search in $GSROOT/Library/Bundles + +Wed Jul 5 20:32:24 2000 Martin Hoerning + + * NSCalendarDate+misc.m: fixed -numberOfWeeksInYear + +Wed Jun 28 15:24:46 2000 Helge Hess + + * NSCalendarDate+misc.m: added -numberOfWeeksInYear + +Tue Jun 13 18:34:04 2000 Helge Hess + + * NGObjCRuntime.m, NSString+Formatting.m: doesn't use stack allocated + buffers anymore + +Fri Jun 9 17:37:09 2000 Helge Hess + + * NGQuotedPrintableCoding.m: changed 'char' type to 'signed char' + +Wed May 31 16:33:53 2000 Helge Hess + + * NSCalendarDate+misc.h: added -firstDayOfMonth and -weekOfMonth + +Wed May 17 11:54:20 2000 Helge Hess + + * NSCalendarDate+misc.m: added -isForenoon and -isAfternoon + +Wed May 3 17:45:19 2000 Helge Hess + + * NSCalendarDate+misc.m: fixed mondays-of-year calculation to respect + the DST timezones + +Wed May 3 17:14:32 2000 Helge Hess + + * NSCalendarDate+misc.m: added week-calculation methods + +Tue May 2 17:24:09 2000 Helge Hess + + * NGBundleManager.m ([NGBundleManager -providedResourcesOfType:inBundle:]): + fixed bug, didn't qualify based on type + +Tue May 2 14:00:45 2000 Jan Reichmann + + * NSString+misc.m: fixed possible buffer overflow bug + +Tue May 2 13:24:40 2000 Jan Reichmann + + * NGHashMap.m: fixed RC-Bug in allObjects and _NGHashMapObjectEnumerator + -nextObject + +Tue May 2 13:12:11 2000 Helge Hess + + * NGHashMap.m: added NSAssert's to check for a valid 'table' + +Fri Apr 28 19:00:52 2000 Helge Hess + + * NSString+misc.m: added placeholder replacement stuff, removed string + debugging stuff + +Wed Apr 12 19:33:26 2000 Helge Hess + + * NSCalendarDate+misc.m: added -isToday method + +Tue Feb 29 17:12:15 2000 Helge Hess + + * MOF3 import + +Mon Feb 21 13:49:40 2000 Helge Hess + + * removed -cString calls + +2000-02-17 + + * NSString+Formatting.m, NSBase64Coding.m, NGBundleManager.m, NSString+misc: + removed a lot of 'cString' usage + +Thu Jan 20 18:44:27 2000 Helge Hess + + * added NGObjCRuntime category. Contains ObjC runtime manipulation stuff + +Mon Jan 10 12:44:10 2000 Helge Hess + + * NSCalendarDate+misc.m: added Y2K support method + +Mon Dec 6 19:15:27 1999 Helge Hess + + * NGBundleManager.m: added support for EOQualifier queries + +Thu Sep 16 18:14:39 1999 Helge Hess + + * removed NGTool.[hm], NGProxy.[hm], NGMainMacros.h + +Mon Jul 26 12:21:44 1999 Helge Hess + + * NGBundleManager.m: added -principalObject method + +Thu Jul 22 14:31:36 1999 Jan Reichmann + + * NGQuotedPrintableCoding.m: fixed NGEncodeQuotedPrintable + +Thu Jul 8 10:23:52 1999 Helge Hess + + * NGBundleManager.m: send notification if bundle did load + +Wed Jun 30 15:20:05 1999 Helge Hess + + * added NGBundleManager + +Fri Jun 25 19:58:14 1999 Helge Hess + + * NSString+Formatting.m: fixed bug (formatter looks for empty format) + +Tue Jun 15 10:38:05 1999 Helge Hess + + * added NGQuotedPrintableCoding categories + +Fri May 21 16:13:52 1999 Helge Hess + + * make it compile with gstep-base + +Fri May 21 13:19:10 1999 Helge Hess + + * changed OPENSTEP macro to WITH_OPENSTEP + +Tue Mar 16 12:43:03 1999 Helge Hess + + * common.h: added support for mingw32 + +Tue Jan 12 13:19:36 1999 Helge Hess + + * NGHashMap.m: added -asDictionary method + +Fri Jan 8 14:42:31 1999 Helge Hess + + * NSSet+enumerator.m: implemented mapping methods + +Thu Jan 7 16:14:55 1999 Helge Hess + + * NGBase64Coding.m: use +stringWithCStringNoCopy:... + +Wed Jan 6 18:54:50 1999 Helge Hess + + * 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 + + * fixed exception creation, cleanups in NSAttributedString + +Mon Dec 28 09:51:24 1998 Helge Hess + + * 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 + + * NSArray+enumerator.m: added methods to create sets using selector + mapping + +Wed Dec 16 12:23:24 1998 Helge Hess + + * NSArray+enumerator.m: added methods to create arrays using selector + mapping + +Fri Dec 11 18:58:35 1998 Helge Hess + + * NSCalendarDate+misc.m: added -hour:minute:second:, -hour:minute: + +Tue Dec 8 19:23:23 1998 Helge Hess + + * 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 + + * NGExtensions.h: added 'index()' function for WIN32 + +Thu Nov 26 13:48:35 1998 Helge Hess + + * NSException+misc.h: removed FINALLY from SYNCHRONIZED macros + + * GNUmakefile: added install capability + +Tue Nov 24 11:51:08 1998 Helge Hess + + * 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 + + * 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 + + * NGCharBuffers.h: fixed bug in initialization + +Fri Nov 13 10:44:03 1998 Helge Hess + + * 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 + + * NGTool.m: signal handler sets itself again after signal is executed + +Fri Nov 6 11:07:03 1998 Helge Hess + + * NGArchiver.m: added proper Copyright information + +Thu Nov 5 08:28:07 1998 Helge Hess + + * NGArchiver.m: reformatted for inclusion in libFoundation + +Wed Oct 28 14:57:40 1998 Helge Hess + + * NGHashMap.m: added -initWithDictionary:, +hashMapWithDictionary: methods + +Thu Oct 22 14:07:32 1998 Helge Hess + + * added NSDictionary+misc category + +Tue Oct 20 19:34:33 1998 Helge Hess + + * added xor digests in MD5 generator + +1998-10-19 Helge Hess + + * 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 + + * 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 + + * started Rhapsody support + +1998-10-10 Helge Hess + + * NGBase64Coding.m: removed generation of newline at end of encoding, + cleaned up, removed MAXLINE constant + +1998-10-09 Helge Hess + + * 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 index 00000000..86762c60 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/.cvsignore @@ -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 index 00000000..7c203340 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOCacheDataSource.m @@ -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 +#import "EODataSource+NGExtensions.h" +#import "common.h" +#include + +@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 index 00000000..6490867a --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOCompoundDataSource.m @@ -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 +#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 index 00000000..63c9dd7c --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EODataSource+NGExtensions.m @@ -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 +#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 index 00000000..20f1a210 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOFetchSpecification+plist.m @@ -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 +#include +#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 index 00000000..1dae5cc0 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOFilterDataSource.m @@ -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 +#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 index 00000000..0c0d69a2 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOGrouping.m @@ -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 index 00000000..4a77e3a0 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOGroupingSet.m @@ -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 index 00000000..dd5c6197 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOKeyGrouping.m @@ -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 index 00000000..91590fa3 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOKeyMapDataSource.m @@ -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 +#include "common.h" +#include + +@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 index 00000000..fa168777 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+CtxEval.m @@ -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 +#import +#include "common.h" + +#if LIB_FOUNDATION_LIBRARY +# import +# import +# import +#elif GNUSTEP_BASE_LIBRARY +# import +#else +# import +# 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 index 00000000..51b9faf1 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifier+plist.m @@ -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 +#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 index 00000000..1a354b1c --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOQualifierGrouping.m @@ -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 +#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)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 index 00000000..c11f3fd1 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOSortOrdering+plist.m @@ -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 +#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 index 00000000..c6fb9cf0 --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/EOTrueQualifier.m @@ -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 index 00000000..7564fddc --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/GNUmakefile @@ -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 index 00000000..1053c38b --- /dev/null +++ b/skyrix-core/NGExtensions/EOExt.subproj/NSArray+EOGrouping.m @@ -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 +#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 index 00000000..86762c60 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/.cvsignore @@ -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 index 00000000..bcaeb874 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/GNUmakefile @@ -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 index 00000000..cba56340 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NGPropertyListParser.m @@ -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 +#include +#include +#include +#endif +#include + +#import "common.h" +#import "NGPropertyListParser.h" +#import "NGMemoryAllocation.h" +//#import "NSObjectMacros.h" +//#import "NSException.h" +#import + +#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 +#import +#import +#import + +@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 +#import +#import +#import + +@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 index 00000000..75971a4e --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSArray+enumerator.m @@ -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 index 00000000..e90d5556 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSAutoreleasePool+misc.m @@ -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 index 00000000..752c8ae1 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSCalendarDate+misc.m @@ -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 index 00000000..e1e35f3a --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSData+gzip.m @@ -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 +#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 index 00000000..286570af --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSData+misc.m @@ -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 index 00000000..cbe6767f --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSDictionary+misc.m @@ -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 index 00000000..3db9e369 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSEnumerator+misc.m @@ -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 +#import +#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)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 index 00000000..c3d78fc6 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSException+misc.m @@ -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 index 00000000..0e1e5e7f --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSFileManager+Extensions.m @@ -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 +#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 index 00000000..a63394df --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSMethodSignature+misc.m @@ -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 index 00000000..bcec3989 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSNull+misc.m @@ -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 +# include +# include +# ifndef GNUSTEP +# import +# endif +#else +# import +#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 @""; +} +- (NSString *)descriptionWithLocale:(id)_locale { + return @""; +} + +#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 index 00000000..792bce31 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Logs.m @@ -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 index 00000000..159b06a3 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSObject+Values.m @@ -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 index 00000000..e8d7ed50 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSProcessInfo+misc.m @@ -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 + +#if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY +# import +#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 index 00000000..d9526c89 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSRunLoop+FileObjects.m @@ -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 +#include "NSRunLoop+FileObjects.h" +#include "FileObjectHolder.h" +#import +#import +#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 index 00000000..e9f0fbe9 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSSet+enumerator.m @@ -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 index 00000000..d02ac2e8 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Encoding.m @@ -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 +#include +#include "common.h" + +#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY +# import +#else +# include +# import +#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 index 00000000..d9498844 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Ext.m @@ -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 + +@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 index 00000000..d244eb65 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+Formatting.m @@ -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("", 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] : @""; + char *buffer = NULL; + unsigned len; + + if (dstr == nil) + return wideString("", 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] : @""; + cstr = (char *)[dstr cString]; + if (cstr == NULL) cstr = ""; + + 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 = ""; + 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 = ""; + + 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 index 00000000..39922ba1 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+German.m @@ -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: /* ü */ + case 220: /* Ü */ + case 228: /* ä */ + case 196: /* Ä */ + case 246: /* ö */ + case 214: /* Ö */ + case 223: /* ß */ + 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 index 00000000..be4864e5 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+HTMLEscaping.m @@ -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: /* ß */ + 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: /* ü */ + 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: /* Ü */ + 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: /* ä */ + 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: /* Ä */ + 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: /* ö */ + 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: /* Ö */ + 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 index 00000000..f6d30d73 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+URLEscaping.m @@ -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 index 00000000..1e9fccf5 --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+XMLEscaping.m @@ -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 index 00000000..0954939d --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSString+misc.m @@ -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 index 00000000..fca96e8d --- /dev/null +++ b/skyrix-core/NGExtensions/FdExt.subproj/NSURL+misc.m @@ -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 index 00000000..46056ff4 --- /dev/null +++ b/skyrix-core/NGExtensions/FileObjectHolder.m @@ -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 +#import +#import +#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 index 00000000..beb6bb54 --- /dev/null +++ b/skyrix-core/NGExtensions/GNUmakefile @@ -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 index 00000000..a76cdf5f --- /dev/null +++ b/skyrix-core/NGExtensions/GNUmakefile.preamble @@ -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 index 00000000..37f0f3d1 --- /dev/null +++ b/skyrix-core/NGExtensions/NGBase64Coding.m @@ -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 +#import + +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 index 00000000..152b78a0 --- /dev/null +++ b/skyrix-core/NGExtensions/NGBitSet.m @@ -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: + @"", + (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 index 00000000..7abeb2f2 --- /dev/null +++ b/skyrix-core/NGExtensions/NGBundleManager.m @@ -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 +#import +#include + +#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 +#endif + +#if NeXT_RUNTIME || APPLE_RUNTIME + +#include + +//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 + +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 index 00000000..1c84b69c --- /dev/null +++ b/skyrix-core/NGExtensions/NGCString.m @@ -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 index 00000000..74e5ce7e --- /dev/null +++ b/skyrix-core/NGExtensions/NGCalendarDateRange.m @@ -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 +#include +#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 index 00000000..2a0cb172 --- /dev/null +++ b/skyrix-core/NGExtensions/NGCustomFileManager.m @@ -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 +#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)_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)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 index 00000000..ee0d2809 --- /dev/null +++ b/skyrix-core/NGExtensions/NGDirectoryEnumerator.m @@ -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 +#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)_fm + path:(NSString *)_path; + +- (NSString *)readdir; + +@end + +@implementation NGDirectoryEnumerator + +- (id)initWithFileManager:(id)_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)_fm { + return [self initWithFileManager:_fm + directoryPath:@"/" + recurseIntoSubdirectories:YES + followSymlinks:NO + prefixFiles:YES]; +} +- (id)initWithFileManager:(id)_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)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 index 00000000..ad6ca31a --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGExtensions + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGExtensions + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGExtensions/NGExtensions.m b/skyrix-core/NGExtensions/NGExtensions.m new file mode 100644 index 00000000..42409ebe --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions.m @@ -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 index 00000000..745a45b8 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/AutoDefines.h @@ -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 index 00000000..2d94e3b8 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/DOMNode+EOQualifier.h @@ -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 + +@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 index 00000000..fd687fb4 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOCacheDataSource.h @@ -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 +#import + +@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 index 00000000..7adf5bbf --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOCompoundDataSource.h @@ -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 + +@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 index 00000000..ffe0f3d8 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EODataSource+NGExtensions.h @@ -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 +#include + +@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 index 00000000..b751c27e --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOFetchSpecification+plist.h @@ -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 + +@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 index 00000000..3dbc6ba0 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOFilterDataSource.h @@ -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 + +@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 index 00000000..4b3abd72 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOGrouping.h @@ -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 + +@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 + +@class NSDictionary; + +@interface NSArray(EOGrouping) +- (NSDictionary *)arrayGroupedBy:(EOGrouping *)_grouping; +@end + +#import + +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 index 00000000..edc08727 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOGroupingSet.h @@ -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 + +#endif /* _EOGroupingSet_h__ */ diff --git a/skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h b/skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h new file mode 100644 index 00000000..10a421f2 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOKeyGrouping.h @@ -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 + +#endif /* _EOKeyGrouping_h__ */ diff --git a/skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h b/skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h new file mode 100644 index 00000000..0e84f8ad --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOKeyMapDataSource.h @@ -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 + +/* + 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 + +@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 index 00000000..311cbd8c --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOQualifier+CtxEval.h @@ -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 +#import + +@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 index 00000000..bc6f11b9 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOQualifier+plist.h @@ -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 + +@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 index 00000000..2eb1f580 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOQualifierGrouping.h @@ -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 + +#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 index 00000000..6e68c001 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOSortOrdering+plist.h @@ -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 + +@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 index 00000000..a841ec39 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/EOTrueQualifier.h @@ -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 + +/* + 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 index 00000000..41c2d5e6 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/FileObjectHolder.h @@ -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 + +@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 index 00000000..9deb3712 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/IndexFunc.h @@ -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 index 00000000..17841d01 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGBase64Coding.h @@ -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 +#import + +/* + 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 index 00000000..e87a49bf --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGBaseTypes.h @@ -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 +#import +#import + +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 index 00000000..f2bd7af4 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGBitSet.h @@ -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 +#import + +@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 index 00000000..8077be0f --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGBundleManager.h @@ -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 +#import +#import +#include + +@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 index 00000000..c3f3e53b --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGCString.h @@ -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 + +@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 index 00000000..37600647 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGCalendarDateRange.h @@ -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 +#import + +@class NSString, NSCalendarDate; + +@interface NGCalendarDateRange : NSObject +{ + 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 index 00000000..9315a332 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGCharBuffers.h @@ -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 +#include +#import +#import +#import + +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 index 00000000..5e76f3c6 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGCustomFileManager.h @@ -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 + +/* + 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 fileManager; +} + +- (id)initWithCustomFileManager:(NGCustomFileManager *)_master + fileManager:(id)_fm; + +- (void)resetMaster; + +/* accessors */ + +- (NGCustomFileManager *)master; +- (id)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 index 00000000..118d2ffd --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGDirectoryEnumerator.h @@ -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 +#include + +/* + 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 fileManager; + + NSMutableArray *enumStack; + NSMutableArray *pathStack; + NSString *currentFileName; + NSString *currentFilePath; + NSString *topPath; + struct { + BOOL isRecursive:1; + BOOL isFollowing:1; + } flags; +} + +- (id)initWithFileManager:(id)_fm + directoryPath:(NSString *)path + recurseIntoSubdirectories:(BOOL)recurse + followSymlinks:(BOOL)follow + prefixFiles:(BOOL)prefix; +- (id)initWithFileManager:(id)_fm; +- (id)initWithFileManager:(id)_fm + directoryPath:(NSString *)_path; + +- (id)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 index 00000000..52839d44 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGExtensions.h @@ -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 + +#if defined(LIB_FOUNDATION_LIBRARY) +# define NoZone nil +#else +# define NoZone NULL +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +// 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 index 00000000..74d08306 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGExtensionsDecls.h @@ -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 index 00000000..efb056ca --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGFileFolderInfoDataSource.h @@ -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 +#import +#include + +@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 index 00000000..e04947f7 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGFileManager.h @@ -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 + +@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 index 00000000..a498d12d --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGFileManagerURL.h @@ -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 /* add GS_EXPORT .. */ +# import /* add NSObject .. */ +#endif + +#import +#include + +/* + 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 fileManager; + NSString *path; +} + +- (id)initWithPath:(NSString *)_path + fileManager:(id)_fm; + +/* accessors */ + +- (id)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 index 00000000..2741fef7 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGHashMap.h @@ -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 +#import + +@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 index 00000000..d32ce815 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGMemoryAllocation.h @@ -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 +#include + +#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 index 00000000..b4a8d7c5 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGMerging.h @@ -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 +#import +#import +#import + +@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 index 00000000..2409c67b --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGObjCRuntime.h @@ -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 + +@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 index 00000000..93c62fab --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGObjectMacros.h @@ -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 index 00000000..07fbdba0 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGPropertyListParser.h @@ -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 + +@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 +#import + +@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 index 00000000..a69e4496 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGQuotedPrintableCoding.h @@ -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 +#import +#include + +/* + 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 index 00000000..5647fda3 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGRule.h @@ -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 + +/* + 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 index 00000000..86d65368 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGRuleAssignment.h @@ -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 + +/* + 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 index 00000000..7cc57b6b --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGRuleContext.h @@ -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 + +/* + 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 index 00000000..a562e2a2 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGRuleEngine.h @@ -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 +#include +#include +#include diff --git a/skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h b/skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h new file mode 100644 index 00000000..f4c7a53d --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGRuleModel.h @@ -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 + +/* + 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 index 00000000..a36b93f4 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGStack.h @@ -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 +#import +#import + +@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 index 00000000..753bcb04 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NGStringScanEnumerator.h @@ -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 +#import + +/* + 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 index 00000000..4da271a8 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSArray+enumerator.h @@ -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 + +@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 index 00000000..28e06600 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSAutoreleasePool+misc.h @@ -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 + +#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 index 00000000..05ca8c92 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSCalendarDate+misc.h @@ -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 + +#if NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY +# import +#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 index 00000000..1aedaff4 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSData+gzip.h @@ -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 + +#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 index 00000000..f259dc18 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSData+misc.h @@ -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 + +@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 index 00000000..569c16dd --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSDictionary+misc.h @@ -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 + +@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 index 00000000..c0c815d5 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSEnumerator+misc.h @@ -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 + +@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 index 00000000..c99a050d --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSException+misc.h @@ -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 +#import + +/* + 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 __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 __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 index 00000000..6743cb60 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSFileManager+Extensions.h @@ -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 +#include + +@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 index 00000000..e2ffaeb2 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSMethodSignature+misc.h @@ -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 + +@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 index 00000000..eb6b3eed --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSNull+misc.h @@ -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 + +@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 index 00000000..4900f388 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSObject+Logs.h @@ -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 +#import + +@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 index 00000000..9324cb29 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSObject+Values.h @@ -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 +#import + +@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 index 00000000..06dbe24b --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSProcessInfo+misc.h @@ -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 + +@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 index 00000000..007cf424 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSRunLoop+FileObjects.h @@ -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 + +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 index 00000000..6aa4ad9f --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSSet+enumerator.h @@ -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 + +@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 index 00000000..38b7c153 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSString+Encoding.h @@ -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 + +/* + 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 index 00000000..f2b877a5 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSString+Ext.h @@ -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 + +/* 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 index 00000000..19a30459 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSString+Formatting.h @@ -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 + +// 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 index 00000000..fe84dec8 --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSString+German.h @@ -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 + +@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 index 00000000..0515ec7e --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSString+misc.h @@ -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 + +@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 index 00000000..3e751b2d --- /dev/null +++ b/skyrix-core/NGExtensions/NGExtensions/NSURL+misc.h @@ -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 // required by gstep-base +#import +#import + +@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 index 00000000..04244fd5 --- /dev/null +++ b/skyrix-core/NGExtensions/NGFileFolderInfoDataSource.m @@ -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 +#import +#import +#import +#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)_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 index 00000000..11016fc3 --- /dev/null +++ b/skyrix-core/NGExtensions/NGFileManager+JS.m @@ -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)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 index 00000000..6d5a42de --- /dev/null +++ b/skyrix-core/NGExtensions/NGFileManager.m @@ -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 index 00000000..127b3aa5 --- /dev/null +++ b/skyrix-core/NGExtensions/NGFileManagerURL.m @@ -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 fileManager; + NSString *path; + BOOL shallCache; + NSURLHandleStatus status; + NSData *cachedData; + NSDictionary *cachedProperties; +} +@end + +@implementation NGFileManagerURL + +- (id)initWithPath:(NSString *)_path + fileManager:(id)_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)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 index 00000000..c6394a28 --- /dev/null +++ b/skyrix-core/NGExtensions/NGHashMap.m @@ -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 +#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 : @""]; + ui = [NSDictionary dictionaryWithObjectsAndKeys: + _self, @"map", + _key ? _key : @"", + @"key", + _object ? _object : @"", + @"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 : @""]; + ui = [NSDictionary dictionaryWithObjectsAndKeys: + _self, @"map", + _key ? _key : @"", + @"key", + _object ? _object : @"", + @"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 : @""]; + ui = [NSDictionary dictionaryWithObjectsAndKeys: + _self, @"map", + _key ? _key : @"", + @"key", + _object ? _object : @"", + @"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 index 00000000..ec39532d --- /dev/null +++ b/skyrix-core/NGExtensions/NGMerging.m @@ -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 +#import + +static NSString *NGCannotMergeWithObjectException = + @"NGCannotMergeWithObjectException"; + +@implementation NSObject(NGMerging) + +- (BOOL)canMergeWithObject:(id)_object { + return ((_object == nil) || (_object == self)) ? YES : NO; +} + +- (id)_makeMergeCopyWithZone:(NSZone *)_zone { + return [(id)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 index 00000000..3003fb60 --- /dev/null +++ b/skyrix-core/NGExtensions/NGObjCRuntime.m @@ -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 +#include +#include +#include "common.h" + +#if NeXT_RUNTIME || APPLE_RUNTIME +# include +# include +typedef struct objc_method_list *MethodList_t; +typedef struct objc_ivar_list *IvarList_t; +typedef struct objc_method *Method_t; +#else +# include +#endif + +#import +#import +#import +#import +#import + +#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 index 00000000..23c0845a --- /dev/null +++ b/skyrix-core/NGExtensions/NGQuotedPrintableCoding.m @@ -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 index 00000000..86762c60 --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/.cvsignore @@ -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 index 00000000..5f466eca --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile @@ -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 index 00000000..6c30acb0 --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRule.m @@ -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 + +@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 index 00000000..549d7d79 --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleAssignment.m @@ -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 index 00000000..d33db7c9 --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleContext.m @@ -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 + +@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)[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 index 00000000..1ab441ed --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleModel.m @@ -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 +#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 index 00000000..bf8d9f5a --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.h @@ -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 +#import + +/* + 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 index 00000000..21bd4ead --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/NGRuleParser.m @@ -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 +#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 index 00000000..906bc085 --- /dev/null +++ b/skyrix-core/NGExtensions/NGRuleEngine.subproj/README @@ -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 index 00000000..9eb9d243 --- /dev/null +++ b/skyrix-core/NGExtensions/NGStack.m @@ -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 index 00000000..c9d6b1a3 --- /dev/null +++ b/skyrix-core/NGExtensions/NGStringScanEnumerator.m @@ -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 + +@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 index 00000000..87801c64 --- /dev/null +++ b/skyrix-core/NGExtensions/SxCore-NGExtensions.graffle @@ -0,0 +1,1616 @@ + + + + + CanvasColor + + w + 1.000000e+00 + + ColumnAlign + 0 + ColumnSpacing + 5.400000e+01 + GraphDocumentVersion + 2 + GraphicsList + + + Bounds + {{5.66667, 9.66667}, {176, 36}} + Class + ShapedGraphic + FitText + YES + ID + 1681 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Class + Group + Graphics + + + Class + Group + Graphics + + + Bounds + {{531, 72}, {135, 18}} + Class + ShapedGraphic + ID + 1677 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{531, 108}, {135, 18}} + Class + ShapedGraphic + ID + 1678 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBundleManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1678 + + ID + 1679 + Points + + {598.5, 90} + {598.5, 108} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1677 + + + + ID + 1676 + + + Bounds + {{531, 36}, {135, 18}} + Class + ShapedGraphic + ID + 1680 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBundleManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 1675 + + + Class + Group + Graphics + + + Bounds + {{603, 504}, {63, 18}} + Class + ShapedGraphic + ID + 1669 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBitSet.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{522, 504}, {63, 18}} + Class + ShapedGraphic + ID + 1670 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGBitSet.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 468}, {63, 18}} + Class + ShapedGraphic + ID + 1671 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{522, 468}, {63, 18}} + Class + ShapedGraphic + ID + 1672 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1670 + + ID + 1673 + Points + + {603, 513} + {585, 513} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 1669 + + + + Class + LineGraphic + Head + + ID + 1672 + + ID + 1674 + Points + + {603, 477} + {585, 477} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 1671 + + + + ID + 1668 + + + Bounds + {{198, 279}, {144, 18}} + Class + ShapedGraphic + ID + 1667 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{36, 324}, {144, 18}} + Class + ShapedGraphic + ID + 1666 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCustomFileManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{36, 279}, {144, 18}} + Class + ShapedGraphic + ID + 1665 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1665 + + ID + 1664 + Points + + {198, 288} + {180, 288} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 1667 + + + + Class + LineGraphic + Head + + ID + 1666 + + ID + 1663 + Points + + {108, 297} + {108, 324} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1665 + + + + Class + Group + Graphics + + + Bounds + {{198, 243}, {126, 18}} + Class + ShapedGraphic + ID + 1661 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManagerURL.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{198, 207}, {126, 18}} + Class + ShapedGraphic + ID + 1662 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 1660 + + + Bounds + {{531, 180}, {135, 18}} + Class + ShapedGraphic + ID + 1659 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteBuffer.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{99, 495}, {126, 18}} + Class + ShapedGraphic + ID + 1652 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOGroupingSet.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{27, 468}, {126, 18}} + Class + ShapedGraphic + ID + 1653 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOQualifierGrouping.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 432}, {126, 18}} + Class + ShapedGraphic + ID + 1654 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOGrouping.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{171, 468}, {126, 18}} + Class + ShapedGraphic + ID + 1655 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOKeyGrouping.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1652 + + ID + 1656 + Points + + {162, 450} + {162, 495} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1654 + + + + Class + LineGraphic + Head + + ID + 1653 + + ID + 1657 + Points + + {144, 450} + {108, 468} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1654 + + + + Class + LineGraphic + Head + + ID + 1655 + + ID + 1658 + Points + + {180, 450} + {216, 468} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1654 + + + + ID + 1651 + + + Bounds + {{531, 153}, {135, 18}} + Class + ShapedGraphic + ID + 1650 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCharBuffer.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{36, 243}, {144, 18}} + Class + ShapedGraphic + ID + 1648 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGDirectoryEnumerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{36, 207}, {144, 18}} + Class + ShapedGraphic + ID + 1649 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 1647 + + + Bounds + {{27, 99}, {171, 18}} + Class + ShapedGraphic + ID + 1646 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOCompoundDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{117, 135}, {171, 18}} + Class + ShapedGraphic + ID + 1645 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOCacheDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{234, 99}, {171, 18}} + Class + ShapedGraphic + ID + 1644 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/EOFilterDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{126, 54}, {171, 18}} + Class + ShapedGraphic + ID + 1643 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h + + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1646 + + ID + 1642 + Points + + {191.7, 72} + {132.3, 99} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1643 + + + + Class + LineGraphic + Head + + ID + 1645 + + ID + 1641 + Points + + {210.5, 72} + {203.5, 135} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1643 + + + + Class + LineGraphic + Head + + ID + 1644 + + ID + 1640 + Points + + {233.1, 72} + {297.9, 99} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1643 + + + + Bounds + {{198, 324}, {171, 18}} + Class + ShapedGraphic + ID + 1639 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileFolderInfoDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 1639 + + ID + 1638 + Points + + {213.9, 72} + {281.1, 324} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1643 + + + + Bounds + {{531, 207}, {135, 18}} + Class + ShapedGraphic + ID + 1637 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGMD5Generator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{522, 441}, {144, 18}} + Class + ShapedGraphic + ID + 1636 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGStack.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{540, 315}, {126, 18}} + Class + ShapedGraphic + ID + 1634 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCString.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{540, 279}, {126, 18}} + Class + ShapedGraphic + ID + 1635 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCString.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 1633 + + + Bounds + {{315, 441}, {162, 18}} + Class + ShapedGraphic + ID + 1632 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGCustomFileManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{522, 360}, {144, 18}} + Class + ShapedGraphic + ID + 1630 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGHashMap.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{522, 396}, {144, 18}} + Class + ShapedGraphic + ID + 1631 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGHashMap.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 1629 + + + Class + LineGraphic + Head + + ID + 1661 + + ID + 1628 + Points + + {261, 225} + {261, 243} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1662 + + + + Class + LineGraphic + Head + + ID + 1648 + + ID + 1627 + Points + + {108, 225} + {108, 243} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1649 + + + + Class + LineGraphic + Head + + ID + 1634 + + ID + 1626 + Points + + {603, 297} + {603, 315} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1635 + + + + Class + LineGraphic + Head + + ID + 1631 + + ID + 1625 + Points + + {594, 378} + {594, 396} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 1630 + + + + GridInfo + + HPages + 1 + ImageCounter + 1 + IsPalette + NO + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + AutoAdjust + YES + HierarchicalOrientation + 0 + MagneticFieldCenter + {0, 0} + + MagnetsEnabled + YES + PageBreakColor + + w + 3.333333e-01 + + PageBreaks + YES + PageSetup + + BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE + hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT + dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE + mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm + nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl + c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp + ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL + TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk + ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv + bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE + mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4BhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh + dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp + boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT + aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQMYgQJkhoaG + + RowAlign + 0 + RowSpacing + 9.000000e+00 + VPages + 1 + WindowInfo + + Frame + {{104, 118}, {794, 751}} + VisibleRegion + {{-159, -179}, {1038.67, 898.667}} + Zoom + 0.75 + + + diff --git a/skyrix-core/NGExtensions/TODO b/skyrix-core/NGExtensions/TODO new file mode 100644 index 00000000..dcc1b192 --- /dev/null +++ b/skyrix-core/NGExtensions/TODO @@ -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 index 00000000..e8b125ef --- /dev/null +++ b/skyrix-core/NGExtensions/Version @@ -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 index 00000000..86762c60 --- /dev/null +++ b/skyrix-core/NGExtensions/XmlExt.subproj/.cvsignore @@ -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 index 00000000..639e0f69 --- /dev/null +++ b/skyrix-core/NGExtensions/XmlExt.subproj/DOMNode+EOQualifier.m @@ -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 +#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)_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)_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 index 00000000..223777f0 --- /dev/null +++ b/skyrix-core/NGExtensions/XmlExt.subproj/GNUmakefile @@ -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 index 00000000..01d1a0df --- /dev/null +++ b/skyrix-core/NGExtensions/common.h @@ -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 +#import + +#if defined(WIN32) +# include +#elif defined(NeXT) || NeXT_Foundation_LIBRARY +# include +#else +# include +#endif + +#if !defined(WIN32) +#include +#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 +# import +# import +# import +# import +# import +#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 +#include +#include +#include +#include + +#ifndef __MINGW32__ +#include +#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 index 00000000..aeefc7ee --- /dev/null +++ b/skyrix-core/NGExtensions/libNGExtensions.def @@ -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 index 00000000..49a10b1a --- /dev/null +++ b/skyrix-core/NGLdap/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGLdap/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-core/NGLdap/COPYRIGHT @@ -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 index 00000000..baaf9db7 --- /dev/null +++ b/skyrix-core/NGLdap/ChangeLog @@ -0,0 +1,173 @@ +2004-06-20 Florian G. Pflug + + * 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 + + * GNUmakefile.preamble: added prebinding (v4.2.16) + +2004-05-05 Marcus Mueller + + * 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 + + * NGLdapConnection.m: fixed various compile warnings with OpenLDAP v2 + (v4.2.14) + +2003-09-07 Marcus Mueller + + * v4.2.13 + + * EOQualifier+LDAP.m: define sel_eq for NeXT_RUNTIME + + * common.h: remove obsolete FoundationExt references + +2003-07-28 Helge Hess + + * 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 + + * NGLdapConnection.m: replaced an indexOfString with rangeOfString + (v4.2.12) + +Wed Apr 16 17:00:06 2003 Jan Reichmann + + * NGLdapConnection.m: move DN for login code in seperate method + (v4.2.11) + +2003-04-15 Helge Hess + + * NGLdapURL.m: small cleanups (v4.2.10) + +2003-04-10 Helge Hess + + * GNUmakefile.preamble: added "nosasl" and "nossl" configuration + parameters + +2003-04-03 Helge Hess + + * 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 + + * 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 + + * NGLdapFileManager.m: replaced a RETAIN macro (v4.2.7) + +2003-01-07 Helge Hess + + * changes for improved compilation on MacOSX, replaced RETAIN macros + with methods (v4.2.6) + +Fri Dec 27 10:55:32 2002 Helge Hess + + * NGLdapAttribute.m: moved UTF8/Latin1 string to NSString conversion to + a centralized method (stringFromData) (v4.2.5) + +2002-11-21 Helge Hess + + * 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 + + * removed all OpenLDAP v1 things not available in v2 anymore ... + (v4.2.2) + +2002-05-23 Helge Hess + + * moved from Skyrix-dev-42 repository to skyrix-core (v4.2.1) + +Thu Apr 25 15:37:57 2002 Helge Hess + + * NGLdapConnection.m: pass credentials as ISO-Latin-1 .. + +Wed Mar 6 13:29:28 CET 2002 Jan41 Reichmann + + * merge with SkyrixGreen + +Mon Jan 21 16:29:30 2002 Jan41 Reichmann + + * NGLdapAttribute.m: + * NGLdapSearchResultEnumerator.m: Fixed UTF8 handling + +Wed Oct 24 12:46:58 2001 Helge Hess + + * changed various places to use UTF-8 instead of cString + + * updated to SKYRiXgreen + +Mon Aug 13 18:01:48 2001 Martin Hoerning + + * 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 + + * NGLdapFileManager.m: inherit from NGFileManager + +Mon Feb 26 17:03:38 2001 Helge Hess + + * NGLdapConnection.m: use port 389 if none is specified + +Mon Jan 29 15:38:23 2001 Helge Hess + + * NGLdapFileManager.m: added (non-)support for trash-folder + +Fri Jan 19 16:15:57 2001 Helge Hess + + * NGLdapFileManager.m: added support for global-ids + +Thu Jan 18 17:08:50 2001 Helge Hess + + * NGLdapFileManager.m: use new FileManager protocols in NGExtensions + +Mon Dec 18 13:02:10 2000 Helge Hess + + * NGLdapEntry.m: added -valueForKey: + +Wed Nov 29 18:06:03 2000 Helge Hess + + * created ChangeLog + diff --git a/skyrix-core/NGLdap/EOQualifier+LDAP.h b/skyrix-core/NGLdap/EOQualifier+LDAP.h new file mode 100644 index 00000000..ec0b91eb --- /dev/null +++ b/skyrix-core/NGLdap/EOQualifier+LDAP.h @@ -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 + +@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 index 00000000..3b4ade0e --- /dev/null +++ b/skyrix-core/NGLdap/EOQualifier+LDAP.m @@ -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 index 00000000..d50d1390 --- /dev/null +++ b/skyrix-core/NGLdap/GNUmakefile @@ -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 index 00000000..2bd83b9f --- /dev/null +++ b/skyrix-core/NGLdap/GNUmakefile.postamble @@ -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 index 00000000..914d90b1 --- /dev/null +++ b/skyrix-core/NGLdap/GNUmakefile.preamble @@ -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 index 00000000..b3a579d2 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdap-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGLdap + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGLdap + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGLdap/NGLdap.h b/skyrix-core/NGLdap/NGLdap.h new file mode 100644 index 00000000..f3e92ded --- /dev/null +++ b/skyrix-core/NGLdap/NGLdap.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __NGLdap_H__ */ diff --git a/skyrix-core/NGLdap/NGLdapAttribute.h b/skyrix-core/NGLdap/NGLdapAttribute.h new file mode 100644 index 00000000..3f859442 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapAttribute.h @@ -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 + +@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 index 00000000..48db9bae --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapAttribute.m @@ -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 index 00000000..991f8ac2 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapConnection+Private.h @@ -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 index 00000000..a187e004 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapConnection.h @@ -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 +#import + +@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 index 00000000..1ec2c345 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapConnection.m @@ -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 + +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 : @"" + 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 index 00000000..c43434b9 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapDataSource.h @@ -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 + +@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 index 00000000..c5ee333f --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapDataSource.m @@ -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 +#import +#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 index 00000000..01828e98 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapEntry.h @@ -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 + +@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 index 00000000..acbdcdc4 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapEntry.m @@ -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 +#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 index 00000000..1e5baccd --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapFileManager.h @@ -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 +#import +#import + +@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 index 00000000..93457e93 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapFileManager.m @@ -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 +#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 +#include + +@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 index 00000000..f9722475 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapGlobalID.h @@ -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 + +@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 index 00000000..fd730cb4 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapGlobalID.m @@ -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 +#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 index 00000000..2799855a --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapModification.h @@ -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 + +@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 index 00000000..a604cb42 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapModification.m @@ -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 index 00000000..614b8ee8 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.h @@ -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 +#import + +@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 index 00000000..fcc6046f --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapSearchResultEnumerator.m @@ -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 + +@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 index 00000000..8072c6d9 --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapURL.h @@ -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 // required by gstep-base +#import + +@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 index 00000000..4652110b --- /dev/null +++ b/skyrix-core/NGLdap/NGLdapURL.m @@ -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 index 00000000..8a16fd21 --- /dev/null +++ b/skyrix-core/NGLdap/NSString+DN.h @@ -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 + +@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 index 00000000..516c9221 --- /dev/null +++ b/skyrix-core/NGLdap/NSString+DN.m @@ -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 index 00000000..3c08dded --- /dev/null +++ b/skyrix-core/NGLdap/README @@ -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 index 00000000..87ad6edf --- /dev/null +++ b/skyrix-core/NGLdap/README.macosx @@ -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 index 00000000..33dfbe1b --- /dev/null +++ b/skyrix-core/NGLdap/Version @@ -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 index 00000000..64c72c45 --- /dev/null +++ b/skyrix-core/NGLdap/common.h @@ -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 +# include +# include +#else +# include +# include +#endif + +#import + +#include +#include + +#endif /* __NGLdap_common_H__ */ diff --git a/skyrix-core/NGMime/.cvsignore b/skyrix-core/NGMime/.cvsignore new file mode 100644 index 00000000..49a10b1a --- /dev/null +++ b/skyrix-core/NGMime/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGMime/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..8e764497 --- /dev/null +++ b/skyrix-core/NGMime/COPYRIGHT @@ -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 index 00000000..0fb32514 --- /dev/null +++ b/skyrix-core/NGMime/ChangeLog @@ -0,0 +1,1244 @@ +2004-08-02 Frank Reppin + + * NGMimeRFC822DateHeaderFieldParser.m: fixed OGo Bug #861 (August + mails were reported as April mails) (v4.2.171) + +2004-07-22 Helge Hess + + * v4.2.170 + + * NGMimeHeaderFieldParser.h: fixed prototypes of + NGMimeHeaderFieldParser protocol + + * NGMimeFileData.m, NGMail: fixed a gcc 3.4 warning + +2004-07-15 Helge Hess + + * 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 + + * 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 + + * NGImap4: fixed a gstep-base warning (v4.2.164) + +2004-06-20 Helge Hess + + * 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 + + * NGImap4: fixed some gcc 3.4 warnings (v4.2.162) + +2004-06-10 Helge Hess + + * NGMail: fixed some gcc 3.4 warnings (v4.2.161) + +2004-06-09 Helge Hess + + * NGMail: minor tweaks (v4.2.160) + + * GNUmakefile.preamble: added prebinding (v4.2.159) + +2004-05-16 Helge Hess + + * 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 + + * 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 + + * 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 + + * NGImap4: some code cleanups, fixed OGo bug #660 (premature dealloc) + (v4.2.154) + +2004-03-19 Helge Hess + + * 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 + + * NGImap4: fixed OGo bug #582 (mail searching was broken) (v4.2.152) + +2004-02-10 Helge Hess + + * NGImap4, NGMail: fixed compilation warnings on OSX (v4.2.151) + +2004-02-08 Helge Hess + + * 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 + + * 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 + + * NGImap4: cleanups, fixed OGo bug #537 (v4.2.145) + +2004-01-21 Helge Hess + + * NGImap4: cleanups, cleanups, cleanups (v4.2.144) + +2004-01-20 Helge Hess + + * NGImap4: cleaned up API (v4.2.143) + +2004-01-20 Helge Hess + + * NGImap4Message: optimization (v4.2.142) + +2004-01-19 Helge Hess + + * NGImap4: various optimizations and cleanups (see NGImap4 ChangeLog + for details) (v4.2.141) + +2004-01-19 Helge Hess + + * added global-id classes in NGImap4 (v4.2.140) + +2004-01-12 Helge Hess + + * 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 + + * 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 + + * NGImap4ResponseParser.m: add parsing of capability entries without + value (v4.2.136) + +2003-11-10 Helge Hess + + * 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 + + * 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 + + * NGImap4Context: temporary set selected folder befor the select action + to prevent notification confusions (v4.2.133) + +2003-10-17 Helge Hess + + * NGImap4: small code cleanups to Sieve client (v4.2.132) + +2003-10-12 Helge Hess + + * GNUmakefile.preamble: added libEOControl as a dependency + (required on MacOSX) (v4.2.131) + +2003-09-06 Helge Hess + + * 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 + + * NGImap4ResponseParser.m: check for empty quota reponses + (v4.2.128) + +2003-07-18 Helge Hess + + * 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 + + * NGImap4ServerRoot: add a missing method + (bulkFetchHeadersFor:inRange:withAllUnread:) (v4.2.126) + +Fri Jun 27 18:08:49 2003 Jan Reichmann + + * NGImap4Message.m: improve flag handling (v4.2.124) + + * NGImap4Message.m: code cleanups (v4.2.123) + +Thu Jun 26 13:23:30 2003 Jan Reichmann + + * 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 + + * 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 + + * NGImap/NGImap4Message+BodyStructure.h: check whether parsing of + date headerfield failed (v4.2.118) + +Fri Jun 13 17:37:37 2003 Jan Reichmann + + * NGMimeType.m: add charset 'unknown' (use us-ascii) (v4.2.117) + +Wed Jun 11 14:49:05 2003 Jan Reichmann + + * 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 + + * 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 + + * NGImap4Folder, NGImap4Functions: add notification for + subfolder-resets (v4.2.112) + +2003-05-28 Helge Hess + + * fixed a linking bug in NGImap4 (due to a ignored warning ...) + (v4.2.111) + +Tue May 27 17:39:20 2003 Jan Reichmann + + * NGImap4Folder.m: check for quota only if folder is selectable + (v4.2.110) + +Tue May 20 18:03:12 2003 Jan Reichmann + + * NGImap4Context; add accessor to set edit default values (v4.2.108) + +Wed May 14 12:54:08 2003 Jan Reichmann + + * 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 + + * 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 + + * media-types: add (v4.2.104) + +Mon May 5 17:59:25 2003 Jan Reichmann + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4: added compilation support for GNUstep base (v4.2.94) + +Fri Feb 28 18:32:53 2003 Jan Reichmann + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4/NGImap4Message.m: select folder befor fetch + body structure (bug 1094) (v4.2.87) + +Mon Feb 17 18:19:06 2003 Jan Reichmann + + * 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 + + * NGImap4Context.m: code cleanups (v4.2.85) + +Wed Feb 5 14:43:22 2003 + + * NGMimePartParser.m: check whether la (called to buffer data) + failed with EndOfStream (bug 993) (v4.2.84) + +Fri Jan 31 17:05:55 2003 + + * 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 + + * 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 + + * NGMimeFileData.m: fixed required includes (v4.2.79) + +Tue Jan 28 15:39:25 2003 + + * 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 + + * 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 + + * NGMimeBodyGenerator.m: add configurable boundary prefix + +2003-01-22 Helge Hess + + * NGMimeMultipartBodyParser.m: use incremental version (v4.2.72) + +Tue Jan 21 19:05:30 2003 + + * 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 + + * NGMimePartGenerator.m: fixed wrong release handling (v4.2.69) + +2003-01-20 Helge Hess + + * 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 + + * NGImap4: fix variable placing (v4.2.66) + +Thu Jan 16 18:36:54 2003 + + * v4.2.65 + + * NGImap4: decode headers values fur bodystructures + + * NGMimePartParser: add +defaultHeaderFieldEncoding + +Tue Jan 14 16:57:28 2003 Jan Reichmann + + * 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 + + * NGMimeType.m: added "koi-r" as an unsupported, but known encoding + (v4.2.62) + +Tue Jan 14 12:24:44 2003 + + * 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 + + * 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 + + * NGPart.h: added some docu to header + +Fri Jan 10 09:54:14 2003 + + * NGImap4: fixed skyrix bug 822, improve error handling (v4.2.58) + +Wed Jan 9 15:26:00 2003 + + * NGImap4: improve parsing to handle over quota warnings + fix skyrix bug 777 (v4.2.57) + +Wed Jan 8 16:26:00 2003 + + * NGImap4: fix skyrix bug 835 (fix quota bugs) (v4.2.56) + +Tue Jan 7 16:47:36 2003 + + * NGImap4: fix skyrix bug 821 (add -usedSpace and -maxQuota to + NGImap4Folder protocol and NGImap4ServerRoot) (v4.2.55) + +2003-01-07 Helge Hess + + * changes for improved compilation on MacOSX, replaced RETAIN macros + with methods (v4.2.54) + +Fri Dec 27 10:53:50 2002 Helge Hess + + * smaller clean ups (v4.2.53) + +Mon Dec 23 15:39:33 2002 Helge Hess + + * NGImap4: small cleanups (v4.2.52) + +2002-12-17 Helge Hess + + * 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 + + * NGImap4: add quota support + +2002-12-07 Helge Hess + + * NGImap4: fixed a compilation warning (v4.2.49) + + * fixed Jan's version numbers + +Tue Dec 10 19:12:45 2002 + + * 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 + + * NGImap4Context.m, NGImap4Client.*, NGImap4ResponseParser: add + capability support (v4.2.46) + +Fri Dec 6 17:08:28 2002 + + * NGImap4Folder (v4.2.45) + + * NGImap4Message: add some ss-sorting improvements + +Tue Dec 3 16:45:14 2002 + + * NGImap4ResponseParser.m: parse empty string if message does + 'no longer exists' (v4.2.44) + +Mon Dec 2 19:22:13 2002 Jan Reichmann + + * 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 + + * NGImap4Folder.m: only reset subfolder if they are already loaded (v4.2.42) + +Fri Nov 29 18:12:32 2002 + + * NGMimePartParser.m: improve error log (v4.2.41) + * NGMail/NGMimeMessageParser.m: fixed quoted printable parsing bug + +Fri Nov 29 12:27:25 2002 + + * NGImap4ResponseParser.m: check tagged responses before parsing + it(v4.2.40) + +Mon Nov 25 16:29:40 2002 Jan Reichmann + + * 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 + + * NGImap4Message*: add support for body-structure content(v4.2.35) + +Fri Nov 22 11:13:40 2002 + + * NGImap4ResponseParser.m: add Imap4MMDataBoundary Default to + modify MM-Data-Use boundary (v4.2.34) + +Tue Nov 21 18:13:38 2002 + + * NGImap4*: memory mapped data (v4.2.33) + * NGImap4*: add fetch bodystructure/single part bodies (v4.2.32) + +2002-11-20 Helge Hess + + * 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 + + * NGImap4*: add commands (thread, fetch body) (v4.2.29) + +Mon Nov 11 10:24:14 2002 Jan Reichmann + + * NGImap4Client.m: improve greetings parse behavior (v4.2.29) + +2002-11-11 Helge Hess + + * NGImap4: initialize objects with URL and SSL support (v4.2.28) + +Wed Oct 30 16:26:46 2002 Jan Reichmann + + * NGMimePartParser.m retain/autorelease values to prevent + RELEASE Exceptions (v4.2.27) + +2002-09-30 Helge Hess + + * v4.2.25 + + * NGMimeHeaderFieldGenerator.m: fixed some compilation warnings + +2002-08-29 Helge Hess + + * NGMimeHeaderFieldGenerator.m: small fix for Jaguar compilation + +Tue Aug 20 18:33:00 2002 Jan41 Reichmann + + * NGMimeHeaderFieldGenerator.m: add default for LF seperated address + entries (v4.2.22) (BUG 17551) + +2002-08-09 Helge Hess + + * 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 + + * 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 + + * NGMime.m: add libraryVersion method + +2002-07-08 Helge Hess + + * removed fix for -valueOfHeaderField:data:, since this breaks + SKYRiXgreen => later + +2002-07-08 Helge Hess + + * 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 + + * NGMimeBodyGenerator.m: remove log + * NGMimeHeaderFieldParser.m: add DateFormat + +Fri Jun 28 16:58:15 2002 Jan41 Reichmann + + * NGMimeBodyParser.m: compares charset caseInsensitive now + +Fri Jun 26 10:40:05 2002 Helge Hess + + * 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 + + * NGMime*: add better encoding handling + +- 2002-06-04 v4.2.4 (jr) [extracted from CVS] + +Tue Jun 4 17:47:30 2002 Jan41 Reichmann + + * NGMimeHeaderFieldParser.m: fixed euro handling + +Fri May 31 16:13:56 2002 Jan41 Reichmann + + * 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 + + * added NGMail, NGImap4 subprojects + +Mon May 6 22:28:21 2002 Helge Hess + + * 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 + + * NGMimeBodyGenerator.m: fixed assertion bug + +Thu Feb 21 13:03:52 2002 Helge Hess + + * NGMimePartParser.m: changed to support -lastException + +Thu Feb 14 11:27:06 2002 Jan41 Reichmann + + * NGMimeHeaderFields.m: supports now ill microsoft content-disposition type + +Tue Dec 18 16:58:11 2001 Helge Hess + + * NGConcreteMimeType.m ([NGConcreteTextMimeType -initWithType:subType:parameters:]): + parse "q" quality parameter + +Tue Dec 18 11:37:15 2001 Helge Hess + + * NGMimeBodyParser.m: added iso-8859-1 as a known charset + +Tue Dec 11 09:53:03 2001 Jan41 Reichmann + + * NGMimeHeaderFieldGenerator.m: fixed string value bug + * NGMimeHeaderFieldParser.m: add date format + +Fri Dec 7 15:17:54 2001 Helge Hess + + * NGMimeBodyGenerator.m: fixed bug with content-type + +Mon Oct 22 19:00:59 2001 Helge Hess + + * NGMimePartParser.m ([NGMimePartParser -parserForBodyOfPart:data:]): + use TextParser only for text/plain bodies + +Mon Oct 22 10:12:45 2001 Helge Hess + + * 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 + + * NGMimeType.m: check for empty mime-type strings ... + +Tue Oct 16 18:59:39 2001 Helge Hess + + * NGMimeHeaderFieldGenerator.m: fixed static-var init bug + +Fri Oct 12 10:36:53 2001 Helge Hess + + * NGMimePartParser.m ([NGMimePartParser -parserForBodyOfPart:data:]): + trim spaces of header-field values ... + +Thu Aug 9 14:21:45 2001 Helge Hess + + * removed java.mail related stuff + +Thu Aug 9 13:22:35 2001 Helge Hess + + * NGMimeFileDataSource.m: use -initWithPath:, no use of NGFileUrl + +Fri Jul 20 15:48:36 2001 Helge Hess + + * NGConcreteMimeType.m: allow parameters in wildcard MIME type + +Fri Apr 6 14:51:41 2001 Jan Reichmann + + * NGMimePartGenerator.m: fixed Autorelease/Release bug + +Wed Mar 28 17:55:21 2001 Jan Reichmann + + * NGMimeHeaderFieldParser.m: add new date formats + +Tue Feb 6 17:08:04 2001 Jan Reichmann + + * NGMimePartParser.m: fixed delegate message bug + +Mon Jan 29 16:27:23 2001 Jan Reichmann + + * NGMimeBodyParser.m, NGMimePartGenerator.m, NGMimePartParser.m: fixed + header encoding bug + +Mon Dec 4 12:19:19 2000 Helge Hess + + * 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 + + * reverted changes from Jun-21 + +Fri Jun 23 12:21:32 2000 Helge Hess + + * NGMimeHeaderFieldParser.m: fixed stmt ordering bug + +Wed Jun 21 23:39:23 2000 Helge Hess + + * removed stack-buffer allocations in various methods + +Tue Jun 13 19:33:31 2000 Helge Hess + + * NGMimeHeaderFields.m: do not use stack-allocated buffers + +Fri Jun 9 17:50:00 2000 Helge Hess + + * GNUmakefile (ADDITIONAL_CPPFLAGS): added -Wall + +Tue Feb 29 18:24:39 2000 Helge Hess + + * MOF3 import + +2000-02-17 + + * NGMimeHeaderFieldGenerator.m, NGMimeType, NGMimePartParser, NGMimeHeaderFields: + removed cString stuff + +Wed Jan 26 11:11:23 2000 Jan Reichmann + + * NGMimeHeaderFieldParser.m: NGMimeRFC822DateHeaderFieldParser returns now + a y2k date + +Mon Oct 25 15:07:36 1999 Helge Hess + + * NGConcreteMimeType.m: fixed bug in NGConcreteTextMimeType, fixed bugs + in -stringValue of multipart-types + +Wed Oct 6 14:19:57 1999 Helge Hess + + * NGConcreteMimeType.m: added support for 'format' parameter in + text/* types + +Mon Oct 4 10:23:32 1999 Helge Hess + + * NGMimePartParser.m: lowercase content-transfer-encoding, to catch both, + 7bit and 7BIT and 7Bit ... + +Fri Oct 1 18:53:43 1999 Helge Hess + + * 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 + + * added class versions and superclass version checks + +Mon Jul 12 22:36:45 1999 Helge Hess + + * NGMimePartGenerator.m: fixed bug (collection was modified while an + enumerator was in use ..) + +Fri Jun 18 19:28:52 1999 Helge Hess + + * NGMimePartParser.m: filter out and apply content-transfer-encoding + +Tue Jun 15 11:22:29 1999 Jan Reichmann + + * 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 + + * 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 + + * NGMimeBodyGenerator.m: fixed bug (add generated boundary to multipart) + +Wed May 26 11:01:48 1999 Jan Reichmann + + * NGMimeBodyGenerator.m fixed nil-body bug + +Fri May 7 20:42:53 1999 Jan Reichmann + + * add -stringValue to NGMimeHeaderFields + +Tue May 4 16:16:47 1999 Helge Hess + + * added MIME generator classes + +Tue May 4 11:43:39 1999 Jan Reichmann + + * NGMimeBodyPartParser.m: fixed remove-comments bug + +Tue May 4 11:30:53 1999 Helge Hess + + * 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 + + * renamed NGMimeParser to NGMimePartParser + +Tue Apr 20 18:27:44 1999 Jan Reichmann + + * NGMimeParser.m: fixed content-length LA-bug + +Tue Apr 20 11:01:27 1999 Jan Reichmann + + * 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 + + * NGMimeParser.m: add delegate for use of content-length-field + fixed read content-length bug + +Fri Apr 16 19:52:46 1999 Helge Hess + + * NGMimeParser.m: improved content-length parsing + +Fri Apr 16 18:48:35 1999 Helge Hess + + * NGMimeParser.m: rewritten to support MIME mails + +Fri Apr 16 12:33:46 1999 Helge Hess + + * 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 + + * use #include instead of #import, made headers #include safe + +Mon Mar 29 11:39:45 1999 Helge Hess + + * added kit class NGMime + + * separate MIME parsers for messages and general MIME. + +Mon Jan 18 20:17:19 1999 Helge Hess + + * NGConcreteMimeType.m: fixed bug in NSConcreteTextMimeType + -parametersAsDictionary method + +Sat Jan 9 21:09:29 1999 Helge Hess + + * NGMimeParser.m: new 'foundEOF' variable + +Tue Dec 15 17:56:40 1998 Helge Hess + + * NGConcreteMimeType.m: fixed -isEqual: of NGConcreteGenericMimeType + +Fri Nov 27 14:50:03 1998 Helge Hess + + * started WIN32 support + +Thu Nov 5 12:25:22 1998 Helge Hess + + * 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 + + * 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 + + * 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 + + * created ChangeLog + diff --git a/skyrix-core/NGMime/GNUmakefile b/skyrix-core/NGMime/GNUmakefile new file mode 100644 index 00000000..523290d2 --- /dev/null +++ b/skyrix-core/NGMime/GNUmakefile @@ -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 index 00000000..9efd299a --- /dev/null +++ b/skyrix-core/NGMime/GNUmakefile.preamble @@ -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 index 00000000..cc283474 --- /dev/null +++ b/skyrix-core/NGMime/NGConcreteMimeType.h @@ -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 +#include + +@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 index 00000000..6f1b0b2d --- /dev/null +++ b/skyrix-core/NGMime/NGConcreteMimeType.m @@ -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 index 00000000..23b45288 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..1c29d8c0 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/ChangeLog @@ -0,0 +1,1062 @@ +2004-07-15 Helge Hess + + * 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 + + * 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 + + * NGImap4FolderMailRegistry.m: fixed a warning with gstep-base + (v4.2.164) + +2004-06-20 Helge Hess + + * NGImap4/NGImap4Message.m: minor optimization (v4.2.163) + +2004-06-14 Helge Hess + + * NGImap4Client.m, NGImap4ResponseParser.m, NSString+Imap4.m: fixed + gcc 3.4 warnings (v4.2.162) + +2004-05-16 Helge Hess + + * NGImap4Context.m, NGImap4FileManager.m, NGImap4Folder.m, + NGImap4Message.m, NGImap4ServerRoot.m, NGSieveClient.m: replaced + "==YES" comparisons (v4.2.158) + +2004-04-02 Helge Hess + + * 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 + + * 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 + + * NGImap4Client.m, NGImap4FolderMailRegistry.m, NGImap4Functions.m, + NGImap4ResponseParser.m, NGSieveClient.m: fixed compilation warnings + on OSX (v4.2.151) + +2004-01-25 Helge Hess + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4Message.m: added various attempts for optimizations (v4.2.142) + +2004-01-19 Helge Hess + + * 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 + + * 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 + + * NGImap4ResponseParser.m: add parsing of capability entries without + value (v4.2.136) + +2003-11-10 Helge Hess + + * 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 + + * 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 + + * NGImap4Context: temporary set selected folder befor the select action + to prevent notification confusions (v4.2.133) + +2003-10-17 Helge Hess + + * NGSieveClient.m: small code cleanups + +Fri Jul 25 13:27:26 2003 Jan Reichmann + + * NGImap4DataSource.h: fixed #define + +Tue Jul 22 15:19:34 2003 Jan Reichmann + + * NGImap4ResponseParser.m: check for empty quota reponses + (v4.2.128) + +2003-07-18 Helge Hess + + * 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 + + * NGImap4ServerRoot: add a missing method + (bulkFetchHeadersFor:inRange:withAllUnread:) (v4.2.126) + +Mon Jun 30 17:45:12 2003 Jan Reichmann + + * 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 + + * NGImap4Message.m: improve flag handling (v4.2.124) + + * NGImap4Message.m: code cleanups (v4.2.123) + +Thu Jun 26 13:23:30 2003 Jan Reichmann + + * 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 + + * 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 + + * v4.2.118 + + * NGImap4Message+BodyStructure.h: check parsing of date failed + + * NGImap4Folder: cleanups + +Mo Jun 02 15:55:20 2003 Jan Reichmann + + * NGImap4Folder, NGImap4Functions: add notification for + subfolder-resets (v4.2.112) + +2003-05-28 Helge Hess + + * NGImap4Folder.m: fixed NSLogL=>NSLog removed a NSLog (v4.2.111) + +Tue May 27 17:39:20 2003 Jan Reichmann + + * NGImap4Folder.m: check for quota only if folder is selectable + (v4.2.110) + +Tue May 20 18:03:12 2003 Jan Reichmann + + * NGImap4Context; add accessor to edit default values (v4.2.108) + +Wed May 14 10:57:51 2003 Jan Reichmann + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4Functions.m: add ImapLogEnabled' default + bind some logs to 'LogImapEnabled' (v4.2.99) + +2003-04-09 Helge Hess + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4Client.m: remove NXConstStr in Excep. Handler (v4.2.91) + +Wed Feb 26 11:37:18 2003 Jan Reichmann + + * 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 + + * 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 + + * NGImap4Message.m: select folder befor fetch body structure (bug 1094) + (v4.2.87) + +Fri Feb 14 16:16:47 2003 Jan Reichmann + + * NGImap4Context.m: code cleanups (v4.2.85) + +Fri Jan 31 17:05:55 2003 + + * NGImap4Context.m: add defaults for imap special folders, + fix folder create bug (v4.2.83) + +Fri Jan 31 14:39:12 2003 + + * NGImap4Folder.m: fetch all messages if no sort failed or no + sortordering was given (v4.2.82) + +Fri Jan 31 12:28:09 2003 + + * v4.2.81 + + * NGImap4Message.m: code cleanups + + * NGImap4Message+BodyStructure.h: fix parsing structure bug + +Wed Jan 29 22:12:08 2003 + + * 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 + + * NGImap4Functions.m: fix courier imap bug (couldn`t delete subfoder + which are selected) (v4.2.78) + +Tue Jan 28 15:54:21 2003 + + * NGImap4Client.m: remove unnecessary abort() (v4.2.77) + +Tue Jan 21 19:05:30 2003 + + * NGImap4Client.m: add sort encoding default + (ImapSortEncoding default: UTF-8) (v4.2.71) + +Tue Jan 21 18:38:09 2003 + + * NGMimeMessageParser: increase version number cause changing of + instance vars of super-class (v4.2.70) + +Fri Jan 17 13:49:17 2003 + + * NGImap4ResponseParser: fix variable placing (v4.2.66) + +Thu Jan 16 18:40:47 2003 + + * NGImap4ResponseParser.m: decode header values fur bodystructures + (v4.2.65) + +Tue Jan 14 18:17:55 2003 + + * v4.2.64 + + * NGImap4Message+BodyStructure.h: lowercase content-transfer-encoding + +Tue Jan 14 12:24:44 2003 + + * 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 + + * v4.2.60 + + * NGImap4Client.m: fix parsing of cyrus version bug (skyrix bug 845) + +Tue Jan 14 09:22:47 2003 + + * NGImap4Message+BodyStructure.h: fixed wong instance var + +Mon Jan 13 19:44:55 2003 + + * NGImap4Message.m, NGImap4Message+BodyStructure.h, + NGImap4FileManager.m: use NGMime header field name contants (v4.2.59) + +Fri Jan 10 09:54:14 2003 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGImap4Client.m: replaced THROW with raise (4.2.51) + +Tue Dec 17 14:46:58 2002 + + * 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 + + * NGImap4Folder.m: added -isComplete prototype to NGImap4Message + Privates (removes a compilation warning) (v4.2.49) + +Tue Dec 10 19:12:45 2002 + + * 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 + + * 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 + + * v4.2.46 + + * NGImap4Context.m: add capability support + + * NGImap4Client.*, NGImap4ResponseParser: add capability command + +Fri Dec 6 17:08:28 2002 + + * 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 + + * NGImap4ResponseParser.m: parse empty string if message does + 'no longer exists'(v4.2.44) + +Mon Dec 2 19:22:13 2002 Jan Reichmann + + * 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 + + * NGImap4Folder.m: only reset subfolder if they are already loaded + (v4.2.42) + +Fri Nov 29 12:27:25 2002 + + * v4.2.40 + + * NGImap4ResponseParser.m: check tagged responses before parsing + it + + * code cleanups + +Wed Nov 27 16:42:07 2002 + + * NGImap4Context.m, NGImap4Folder: add msn-uid cache (v4.2.39) + +Mon Nov 25 16:29:40 2002 Jan Reichmann + + * 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 + + * 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 + + * NGImap4ResponseParser.m: add Imap4MMDataBoundary Default to + modify MM-Data-Use boundary (v4.2.34) + +Thu Nov 21 20:02:48 2002 + + * 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 + + * add fetch body structure with content-urls + + * add fetch content of single parts (v4.2.32) + +Wed Nov 20 18:07:37 2002 + + * GNUmakefile: remove tool-make + +2002-11-20 Helge Hess + + * 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 + + * NGImap4*: add commands (thread, fetch body) + +Mon Nov 11 10:24:14 2002 Jan Reichmann + + * NGImap4Client.m: improve greetings parse behaviour + +2002-11-10 Helge Hess + + * NGImap4Client, NGImap4FileManager: can init with URL (v4.2.27) + +2002-09-30 Helge Hess + + * 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 + + * (from 4.1) use cyrus 2.0, sieve, fixes (v4.2.23) + +Tue Aug 20 14:57:38 2002 Jan Reichmann + + * 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 + + * 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 + + * 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 + + * NGImap4Folder, NGImap4Client, NGImap4ResponseParser: add + sortedMessagesInRange Method + +- 2002-07-10 v4.2.16 (hh) [extracted from CVS] + +2002-07-09 Helge Hess + + * 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 + + * NGImap4Context: add folderWithName:caseInsensitive: (v4.2.11) + +Tue Jun 11 16:17:06 2002 Jan Reichmann + + * NGImap4Client.m: (bug 11939) add quote support for special + chars in passwd (v4.2.10) + +Mon Jun 10 18:58:55 2002 Jan Reichmann + + * 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 + + * 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 + + * 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 + + * merge with SkyrixGreen + +Mon Jan 7 16:57:07 2002 Jan Reichmann + + * NGImap4ResponseParser.m: improved error messages + +Fri Dec 7 14:14:33 2001 Jan Reichmann + + * NGImap4Client.m ([NGImap -fetchFrom:to:parts:]): add profiling + +Tue Dec 4 19:14:43 2001 Jan Reichmann + + * NGImap4Client.m ([NGImap -fetchFrom:to:parts:]): passwd with spaces + +Wed Nov 28 18:17:06 2001 Gerrit Albrecht + + * NGImap4Context.m, NGImap4FileManager.m: Added knowledge + about drafts folder. + +Wed Oct 24 13:18:29 2001 Helge Hess + + * 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 + + * NGImap4Context.m: Fixed __RELEASE__ bug ;( + +Fri Aug 10 13:48:29 2001 Helge Hess + + * NGImap4FileManager.m: inherit from NGFileManager + +Fri Aug 10 07:28:10 2001 Martin Hoerning + + * NGImap4Client, NGImap4FileManager, NGImap4Context: + RETAIN-BUGS fixed + +Fri Jun 22 15:46:23 2001 Jan Reichmann + + * NGImap4Client.m: fixed search uid bug + +Thu Jun 21 16:50:13 2001 Jan Reichmann + + * NGImap4FileManager.m: add -imapContext + +Wed May 16 17:59:00 2001 Jan Reichmann + + * NGImap4Client.m, NGImap4Context.m, NGImap4ResponseParser.m: + washington imap server + +Tue May 15 18:10:33 2001 Jan Reichmann + + + * NGImap4ResponseParser.m: ignore now empty fetchentries with no + header length field + +Tue May 8 16:26:13 2001 Jan Reichmann + + * NGImap4FileManager.m: add edit possibility for syncMode + +Mon Apr 17 11:17:47 2001 Jan Reichmann + + * NGImap4Folder.m: fixed error log bug + +Mon Apr 2 13:47:47 2001 Jan Reichmann + + * NGImap4FileManager.m: fixed private interface + +Fri Mar 30 14:17:25 2001 Jan Reichmann + + * 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 + + * NGImap4DataSource.m: major cleanups + +Fri Mar 16 16:05:27 2001 Jan Reichmann + + * NGImap4Message.m: fixed parse message bug + +Wed Mar 14 13:16:24 2001 Jan Reichmann + + * NGImap4FileManager.m: add datasource at path + +Tue Feb 6 19:47:03 2001 Jan Reichmann + + * NGImap4Folder.m: fixed bug for wrong MSN + +Tue Feb 6 19:47:03 2001 Joerg Grimm + + * NGImap4Client.m: check open connection response without + servername (Cyrus IMAP4 v) + +Wed Jan 3 13:14:43 2001 Jan Reichmann + + * NGImap4Client.m: fixed flag bug + +Tue Jan 2 16:58:46 2001 Jan Reichmann + + * NGImap4Client.m: hide password in log + + * NGImap4Client.m: sleep before reconnect + +Mon Dec 18 14:48:18 2000 Jan Reichmann + + * NGImap4Folder.m: fixed 'lookup only' folder bug + +Fri Dec 15 19:26:09 2000 Jan Reichmann + + * NGImap4Client.m, NGImap4Context.m: automatically subscribe to inbox + + * NGImap4Context.m: format text + +Mon Nov 13 14:51:13 2000 Jan Reichmann + + * Python/: insert python module + * NGImapClient.m: enable append of messages with more than 15kB + +Fri Sep 29 15:15:29 2000 Jan Reichmann + + * NGImap4: add sync mode (synchronize selects for folder) + +Thu Sep 14 13:33:49 2000 Jan Reichmann + + * search.txt: use '=' instead of '==' + + * NGImap4Context.[hm]: insert - newMessages + + * NGImap4Client.m: remove compiler warning + +Wed Sep 13 14:47:23 2000 Jan Reichmann + + * NGImap4Context.m: at first ask inbox in method hasNewMessages + +Tue Sep 5 14:04:37 2000 Joerg Grimm + + * NGImap4Folder.m: log removed + +Fri Sep 1 13:15:22 2000 Jan Reichmann + + * NGImap4Client.m: remove logs + +Wed Aug 30 21:22:31 2000 Jan Reichmann + + * NGImap4Context.[hm], NGImap4Client.m: store server data + +Tue Aug 29 18:56:38 2000 Jan Reichmann + + * NGImap4Context.m, NGImap4Folder.h, NGImap4Folder.m,NGImap4Functions.m: + actions for no-select folders + +Mon Aug 28 18:43:11 2000 Jan Reichmann + + * NGImap4Folder.m: fixed bug for read-only folder + +Tue Aug 8 11:21:16 2000 Helge Hess + + * NGImap4Message.m: added -globalID method + + * NGImap4Context.m: added -login method + +Thu Jul 27 14:48:26 2000 Jan Reichmann + + * NGImap4Folder.m: fixed bug (unseen was not updated) + +Fri Jun 23 10:32:00 2000 Jan Reichmann + + * NGImap4ResponseParser.m: remove category for NSData + +Wed Jun 7 16:07:03 2000 Jan Reichmann + + * NGImap4Folder.[hm], NGImap4ServerRoot.[hm]: maxResults for search + +Mon May 29 17:56:46 2000 Jan Reichmann + + * NGImap4Functions.m: remove recursive copy bug + +Sat May 27 18:27:48 2000 Jan Reichmann + + * NGImap4Message.m: add flagged methods + +Tue May 23 12:33:25 2000 Jan Reichmann + + * NGImap4Context.[hm]: improvements ( add -folderWithName) + +Fri May 19 11:52:25 2000 Jan Reichmann + + * NGImap4Client.m: replace 0 with 1 in range-commands + +Thu May 18 15:20:19 2000 Jan Reichmann + + * NGImap4*: enabled mailboxes with more than one rootfolder + +Tue May 16 12:35:46 2000 Jan Reichmann + + * NGImap4Client.m: fixed RC bug + +Mon May 15 16:26:19 2000 Jan Reichmann + + * NGImap4Context.m, NGImap4Folder.[hm]: evaluate noinferiors flag + +Wed May 10 19:30:37 2000 Jan Reichmann + + * NGImap4Folder.m: fixed RC-bug (raised during moveFolder) + +Wed May 3 22:15:10 2000 Jan Reichmann + + * NGImap4Folder.m: improvements + +Mon May 1 21:24:21 2000 Jan Reichmann + + * NGImap4Folder.m: fixed RC-bug + +Wed Apr 26 10:26:54 2000 Jan Reichmann + + * NGImap4Context.m: bugfix in hasNewMessages + +Thu Apr 13 16:19:56 2000 Jan Reichmann + + * NGImap4Message.m: insert isEqual: and hash methods + +Mon Apr 10 14:34:49 2000 Helge Hess + + * 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 + + * NGImap4 build lib-internal Trash/Sent Folder managment + +Tue Feb 29 19:18:09 2000 Helge Hess + + * MOF3 import + +Tue Feb 22 19:16:11 2000 Helge Hess + + * GNUmakefile (GNUSTEP_INSTALLATION_DIR): changed to GNUSTEP_LOCAL_ROOT + +Thu Jan 13 17:24:40 2000 Jan Reichmann + + * created ChangeLog diff --git a/skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m b/skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m new file mode 100644 index 00000000..57c9eaef --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/EOQualifier+IMAPAdditions.m @@ -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 index 00000000..2506b3e0 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/GNUmakefile @@ -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 index 00000000..b97e78b5 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGImap4 + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGImap4 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGMime/NGImap4/NGImap4.h b/skyrix-core/NGMime/NGImap4/NGImap4.h new file mode 100644 index 00000000..b9d37453 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4.h @@ -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 +#include +#include +#include +#include + +// 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 index 00000000..b41899ec --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4.m @@ -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 + +@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 index 00000000..4cff2b42 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Client.h @@ -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 +#include +#include +#include + +/* + 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 socket; + id text; + id 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)_address; ++ (id)clientWithHost:(id)_host; + +- (id)initWithURL:(NSURL *)_url; +- (id)initWithHost:(id)_host; +- (id)initWithAddress:(id)_address; + +/* equality */ + +- (BOOL)isEqualToClient:(NGImap4Client *)_obj; + +/* accessors */ + +- (id)socket; +- (id)address; +- (NSString *)delimiter; +- (EOGlobalID *)serverGlobalID; + +/* notifications */ + +- (void)registerForResponseNotification:(id)_obj; +- (void)removeFromResponseNotification:(id)_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 index 00000000..879ac19c --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Client.m @@ -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 + +#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 +#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)_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)_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)socket { + return self->socket; +} + +- (id)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] : 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)_obj { + [self->responseReceiver addObject:[NSValue valueWithNonretainedObject:_obj]]; +} + +- (void)removeFromResponseNotification:(id)_obj { + [self->responseReceiver removeObject: + [NSValue valueWithNonretainedObject:_obj]]; +} + +- (void)sendResponseNotification:(NGHashMap *)_map { + NSValue *val; + id 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] : 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)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 index 00000000..d0599874 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Context.h @@ -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 +#include + +@class NSDictionary, NGHashMap, NSMutableArray, NSURL, NSException; +@class EOGlobalID; +@class NGImap4Client, NGImap4Folder, NGImap4ServerRoot; + +@interface NGImap4Context : NSObject +{ + 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 index 00000000..2f77c50b --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Context.m @@ -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 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 index 00000000..7bb90c88 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4DataSource.h @@ -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 +#import + +@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 index 00000000..31aacfb3 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4DataSource.m @@ -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 +#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 index 00000000..6d58b66f --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FileManager.h @@ -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 +#include + +@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 index 00000000..f72d8b75 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FileManager.m @@ -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 +#include +#include +#include +#include "imCommon.h" +#include + +@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)_lookupFolderAtPath:(NSArray *)_paths { + NSEnumerator *e; + NSString *path; + id 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)_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 index 00000000..62e50dd5 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Folder.h @@ -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 +#import +#import + +#define USE_MESSAGE_CACHE 0 + +@class NSArray, NSString, NSMutableArray, NSNumber; +@class EOGlobalID, EOQualifier; +@class NGHashMap; +@class NGImap4Context, NGImap4Message, NGImap4FolderMailRegistry; +@class NGImap4FolderFlags; + +@interface NGImap4Folder : NSObject +{ +@private + NGImap4FolderFlags *flags; + NSString *name; + NSURL *url; + EOGlobalID *globalID; + NGImap4Context *context; + NSArray *subFolders; + + NSArray *msn2UidCache; + + id 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)_folder; + +- (BOOL)isEqual:(id)_obj; +- (BOOL)isEqualToImap4Folder:(NGImap4Folder *)_folder; + +/* accessors */ + +- (NGImap4Context *)context; +- (NSException *)lastException; +- (void)resetLastException; +- (id)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 index 00000000..b96b1ad3 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Folder.m @@ -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)_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)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 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 index 00000000..cb7dff9d --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.h @@ -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 + +@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 index 00000000..f3ce1e64 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderFlags.m @@ -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 index 00000000..3ee8274a --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.h @@ -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 + +@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 index 00000000..701abed1 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderGlobalID.m @@ -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 index 00000000..584bafd4 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.h @@ -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 + +@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 index 00000000..c3d29f5f --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4FolderMailRegistry.m @@ -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 index 00000000..dad32797 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Functions.h @@ -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 +#include + +@class NSString, NSException; + +@interface NGImap4FolderHandler : NSObject + ++ (id)sharedImap4FolderHandler; + +- (NGImap4Folder *)subfolderWithName:(NSString *)_name + parentFolder:(id)_parent + ignoreCase:(BOOL)_caseIns; + +- (BOOL)isFolder:(id)_child + aSubfolderOf:(id)_parent; + +- (NSException *)createSubfolderWithName:(NSString *)_name + parentFolder:(id)_parent + append:(BOOL)_append; + +@end + +NGImap4Folder *_subFolderWithName(id self, NSString *_name, + BOOL _caseIns); +BOOL _checkResult(NGImap4Context *_ctx, NSDictionary *_dict, + const char *_command); +BOOL _isSubFolder(id self, id_folder); +BOOL _hasNewMessagesInSubFolder(id self, BOOL _fetch); +BOOL _hasUnseenMessagesInSubFolder(id self, BOOL _fetch); +BOOL _deleteSubFolder(id self, NGImap4Folder *_folder); +BOOL _copySubFolder(id self, + id _f, id _toFolder); +BOOL _moveSubFolder(id self, NGImap4Folder *_f, + id_folder); +BOOL _createSubFolderWithName(id 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 index 00000000..3647ca1b --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Functions.m @@ -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 +#include +#include +#include +#include +#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)_child + aSubfolderOf:(id)_parent +{ + return _isSubFolder(_parent, _child); +} +BOOL _isSubFolder(id parentFolder, id_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)_parent + ignoreCase:(BOOL)_caseIns +{ + return _subFolderWithName(_parent, _name, _caseIns); +} +NGImap4Folder *_subFolderWithName +(id _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 _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 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 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 self, + id _f, id _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 self, NGImap4Folder *_f, + id_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 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)_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 index 00000000..caa2eb73 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Message+BodyStructure.h @@ -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_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_part); +@end /* NGImap4Message(BodyStructure) */ + +@implementation NGImap4Message(BodyStructure) + +static id _buildMultipartMessage(id self, NSURL *_baseUrl, NSDictionary *_dict, + id_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_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 index 00000000..2a6d1034 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Message.h @@ -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 +#include +#include + +@class NSArray, NSMutableDictionary; +@class EOGlobalID; +@class NGHashMap; +@class NGImap4Context, NGImap4Folder, NGImap4FolderMailRegistry; + +@interface NGImap4Message : NSObject +{ +@protected + NGHashMap *headers; + unsigned uid; + int size; + NSArray *flags; + + id message; + id 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)bodyStructure; +- (id)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 index 00000000..71c1b059 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Message.m @@ -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 +#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)bodyStructure { + if (self->bodyStructure == nil) + [self generateBodyStructure]; + + return self->bodyStructure; +} + +- (id)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 index 00000000..d065a4ec --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.h @@ -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 + +@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 index 00000000..bbd862a7 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4MessageGlobalID.m @@ -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 index 00000000..aea0d107 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.h @@ -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 + +@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 index 00000000..1176a0d5 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ResponseNormalizer.m @@ -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 index 00000000..f716852f --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.h @@ -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 +#import +#include +#include + +@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)_stream; +- (id)initWithStream:(id)_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 index 00000000..422f6662 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ResponseParser.m @@ -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)_stream { + NGImap4ResponseParser *parser; + + parser = [NGImap4ResponseParser alloc]; /* seperate line to keep gcc happy */ + return [[parser initWithStream:_stream] autorelease]; +} + +- (id)initWithStream:(id)_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 index 00000000..63950b73 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.h @@ -0,0 +1,32 @@ +// $Id$ + +#ifndef __NGImap4_NGImap4ServerGlobalID_H__ +#define __NGImap4_NGImap4ServerGlobalID_H__ + +#include + +@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 index 00000000..974ce1bb --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ServerGlobalID.m @@ -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 index 00000000..b8d8437d --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.h @@ -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 +#include +#include + +@class NSArray, NSString, NSMutableArray, NSNumber; +@class NGHashMap, NGImap4Context, EOQualifier; + +@interface NGImap4ServerRoot : NSObject +{ +@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 index 00000000..b11f22da --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4ServerRoot.m @@ -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)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)_folder { + return _copySubFolder(self, _f, _folder); +} + +- (BOOL)moveSubFolder:(NGImap4Folder *)_f to:(id)_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 index 00000000..e692ae6e --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Support.h @@ -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 + +@class NSDictionary, NSString, NSArray, EOQualifier, NSNumber, NSData; +@class NGImap4Client, NGImap4Context, NGImap4Folder; + +@protocol NGImap4Folder + +- (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 index 00000000..c4b471f3 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGImap4Support.m @@ -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 index 00000000..d44c7205 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGSieveClient.h @@ -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 +#include +#include +#include +#include + +@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 socket; + id text; + id address; + NGImap4ResponseParser *parser; + + BOOL isLogin; + + NSString *login; + NSString *password; + + BOOL debug; +} + ++ (id)clientWithAddress:(id)_address; ++ (id)clientWithHost:(id)_host; + +- (id)initWithHost:(id)_host; +- (id)initWithAddress:(id)_address; + +// equality + +- (BOOL)isEqual:(id)_obj; +- (BOOL)isEqualToSieveClient:(NGSieveClient *)_obj; + +// accessors + +- (id)socket; +- (id)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 index 00000000..a25db587 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NGSieveClient.m @@ -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 + +#include "NGSieveClient.h" +#include "NGImap4Support.h" +#include "NGImap4ResponseParser.h" +#include "NSString+Imap4.h" +#include "imCommon.h" +#include + +@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)_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)_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)socket { + return self->socket; +} + +- (id)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] : 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:@"", + (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] : 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 index 00000000..cecde8e3 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NSString+Imap4.h @@ -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 + +@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 index 00000000..e49966c9 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/NSString+Imap4.m @@ -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 +#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 index 00000000..820d063e --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/README @@ -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 + 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 index 00000000..53516c6d --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/SxCore-NGImap4Flow.graffle @@ -0,0 +1,4186 @@ + + + + + CanvasColor + + a + 1 + w + 1 + + ColumnAlign + 0 + ColumnSpacing + 3.600000e+01 + GraphDocumentVersion + 2 + GraphicsList + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2369 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.712345e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {698.143, 216} + {702, 270} + {612, 360} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2314 + + + + Bounds + {{593, 501}, {170, 15}} + Class + ShapedGraphic + FitText + YES + ID + 2368 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2367 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 3.028804e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {686.571, 216} + {621, 270} + {604.636, 360} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2314 + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2366 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 3.361621e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {639, 207} + {549, 207} + {450, 207} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2314 + + + + Class + LineGraphic + Head + + ID + 2318 + + ID + 2365 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.675532e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {374.25, 486} + {333, 441} + {182.571, 387} + + Style + + stroke + + HeadArrow + FilledDoubleArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2361 + + + + Class + LineGraphic + Head + + ID + 2318 + + ID + 2364 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.175532e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {348, 486} + {279, 468} + {169.65, 387} + + Style + + stroke + + HeadArrow + FilledDoubleArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2361 + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2363 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.270993e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {403.714, 486} + {531, 432} + {592.714, 378} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2361 + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2362 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.958656e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {627, 378} + {675, 396} + {684, 360} + {647.902, 364.011} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2312 + + + + Bounds + {{324, 486}, {117, 18}} + Class + ShapedGraphic + ID + 2361 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2319 + + ID + 2360 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.553997e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {354.157, 108} + {437.776, 63} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Class + LineGraphic + Head + + ID + 2319 + + ID + 2359 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.183397e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {594, 52.5681} + {522, 53.3071} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2358 + + + + Bounds + {{594, 45}, {81, 18}} + Class + ShapedGraphic + ID + 2358 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2356 + + ID + 2357 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.346480e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {162, 387} + {198, 459} + {150.75, 486} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Bounds + {{99, 486}, {72, 18}} + Class + ShapedGraphic + ID + 2356 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{9, 432}, {63, 18}} + Class + ShapedGraphic + ID + 2355 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2354 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 1.303191e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {213.076, 386.55} + {450, 423} + {577.5, 378} + + Style + + stroke + + HeadArrow + Arrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Class + LineGraphic + Head + + ID + 2352 + + ID + 2353 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.187268e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {141.094, 369} + {61.0156, 324} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Bounds + {{9, 306}, {72, 18}} + Class + ShapedGraphic + ID + 2352 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2351 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.607856e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {160.8, 369} + {207, 243} + {361.812, 214.852} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Class + LineGraphic + Head + + ID + 2349 + + ID + 2350 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.547872e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {114.75, 387} + {72, 396} + {51.75, 369} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Bounds + {{9, 351}, {72, 18}} + Class + ShapedGraphic + ID + 2349 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2346 + + ID + 2348 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 8.856383e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {154.269, 387} + {138.212, 432} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Class + LineGraphic + Head + + ID + 2345 + + ID + 2347 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.409575e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {152.975, 369} + {130.496, 324} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + Bounds + {{99, 432}, {72, 18}} + Class + ShapedGraphic + ID + 2346 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{90, 306}, {72, 18}} + Class + ShapedGraphic + ID + 2345 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2311 + + ID + 2344 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 8.111702e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {558, 371.647} + {450, 378} + {412.5, 333} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2312 + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2343 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.654255e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {601.2, 360} + {576, 234} + {449.035, 213.953} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2312 + + + + Class + LineGraphic + Head + + ID + 2341 + + ID + 2342 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.496911e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {613.249, 378} + {696.139, 450} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2312 + + + + Bounds + {{675, 450}, {63, 18}} + Class + ShapedGraphic + ID + 2341 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2340 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 3.962766e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {288, 342} + {288, 270} + {388.286, 216} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2310 + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2339 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 1.356383e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {312, 360} + {432, 405} + {561.436, 377.75} + + Style + + stroke + + HeadArrow + FilledDoubleArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2310 + + + + Class + LineGraphic + Head + + ID + 2337 + + ID + 2338 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.711531e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {336.899, 108} + {333.9, 63} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Bounds + {{297, 36}, {72, 27}} + Class + ShapedGraphic + ID + 2337 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2336 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.311450e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {336.24, 126} + {331.2, 162} + {390.24, 198} + + Style + + stroke + + HeadArrow + Arrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Class + LineGraphic + Head + + ID + 2307 + + ID + 2335 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.381792e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {320.4, 126} + {252, 162} + {252, 189} + + Style + + stroke + + HeadArrow + FilledDoubleArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Class + LineGraphic + Head + + ID + 2332 + + ID + 2334 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 6.478347e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {305.906, 108} + {201.257, 78.5482} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Class + LineGraphic + Head + + ID + 2330 + + ID + 2333 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 4.899368e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {162, 81} + {162, 126} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2332 + + + + Bounds + {{117, 54}, {90, 27}} + Class + ShapedGraphic + ID + 2332 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2330 + + ID + 2331 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 5.183075e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {297.102, 122.01} + {197.362, 134.922} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2326 + + + + Bounds + {{126, 126}, {72, 27}} + Class + ShapedGraphic + ID + 2330 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2328 + + ID + 2329 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 7.845744e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {414, 198} + {513, 99} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Bounds + {{477, 81}, {90, 18}} + Class + ShapedGraphic + ID + 2328 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2326 + + ID + 2327 + Points + + {398.261, 198} + {344.251, 126} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Bounds + {{297, 108}, {81, 18}} + Class + ShapedGraphic + ID + 2326 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2310 + + ID + 2325 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 2.739362e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {397.685, 216} + {295.312, 342} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2324 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 3.803191e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {423, 216} + {549, 279} + {597.6, 360} + + Style + + stroke + + HeadArrow + Arrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Class + LineGraphic + Head + + ID + 2311 + + ID + 2323 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 2.632979e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {412, 216} + {468, 288} + {420.75, 315} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Class + LineGraphic + Head + + ID + 2311 + + ID + 2322 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 7.526596e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {405, 216} + {405, 315} + + Style + + stroke + + HeadArrow + FilledDoubleArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Class + LineGraphic + Head + + ID + 2320 + + ID + 2321 + Labels + + + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 7.367021e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {422.053, 198} + {541.421, 135} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2306 + + + + Bounds + {{522, 108}, {90, 27}} + Class + ShapedGraphic + ID + 2320 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundRect + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{387, 45}, {135, 18}} + Class + ShapedGraphic + ID + 2319 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ResponseParser.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Bounds + {{99, 369}, {117, 18}} + Class + ShapedGraphic + ID + 2318 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Message.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Bounds + {{675, 135}, {81, 18}} + Class + ShapedGraphic + ID + 2317 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + Rectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{675, 162}, {81, 18}} + Class + ShapedGraphic + ID + 2316 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + a + 1 + b + 0.5 + g + 1 + r + 1 + + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2316 + + ID + 2315 + Points + + {715.5, 153} + {715.5, 162} + + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2317 + + + + Bounds + {{639, 198}, {117, 18}} + Class + ShapedGraphic + ID + 2314 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2314 + + ID + 2313 + Points + + {711, 180} + {702, 198} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 2316 + + + + Bounds + {{558, 360}, {90, 18}} + Class + ShapedGraphic + ID + 2312 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Folder.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Bounds + {{360, 315}, {90, 18}} + Class + ShapedGraphic + ID + 2311 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + Rectangle + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{234, 342}, {108, 18}} + Class + ShapedGraphic + ID + 2310 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ServerRoot.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2312 + + ID + 2309 + Points + + {442.344, 333} + {562.846, 360.002} + + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2311 + + + + Class + LineGraphic + Head + + ID + 2310 + + ID + 2308 + Points + + {375.979, 333} + {331.99, 342} + + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2311 + + + + Bounds + {{180, 189}, {144, 18}} + Class + ShapedGraphic + ID + 2307 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + Rectangle + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + + + Text + + Text + {\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} + + + + Bounds + {{360, 198}, {90, 18}} + Class + ShapedGraphic + ID + 2306 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Context.h + + Shape + RoundedRectangle + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2306 + + ID + 2305 + Points + + {324, 201.717} + {360, 204.065} + + Style + + stroke + + Color + + a + 1 + b + 0 + g + 0 + r + 1 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 2307 + + + + Bounds + {{8.75, 10}, {117, 36}} + Class + ShapedGraphic + FitText + YES + ID + 2304 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Class + LineGraphic + Head + + ID + 2355 + + ID + 2303 + Labels + + + FixedWidth + 2.300000e+01 + Label + + Align + 0 + Text + {\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} + + LabelVisible + YES + Offset + 0.000000e+00 + Position + 7.302684e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 1.000000e-01 + + + Label + + Align + 0 + + Offset + 0.000000e+00 + Position + 9.000000e-01 + + + Points + + {141.25, 387} + {57.2917, 432} + + Style + + stroke + + HeadArrow + FilledArrow + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 2318 + + + + GridInfo + + HPages + 1 + ImageCounter + 1 + IsPalette + NO + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + AutoAdjust + YES + MagneticFieldCenter + {0, 0} + + MagnetsEnabled + YES + PageBreakColor + + a + 1 + w + 0.666667 + + PageBreaks + YES + PageSetup + + 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 + + RowAlign + 0 + RowSpacing + 3.600000e+01 + VPages + 1 + WindowInfo + + Frame + {{-4, 56}, {913, 794}} + VisibleRegion + {{-64, -97}, {898, 717}} + Zoom + 1 + + + diff --git a/skyrix-core/NGMime/NGImap4/TODO b/skyrix-core/NGMime/NGImap4/TODO new file mode 100644 index 00000000..a30bbc4a --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/TODO @@ -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 index 00000000..0d4f4983 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/imCommon.h @@ -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 + +#if LIB_FOUNDATION_LIBRARY +# include +#elif NeXT_Foundation_LIBRARY +# import +# import +# if 0 /* no more FoundationExt */ +# import +# import +# import +# endif +#endif + +#include +#include +#include +#include +#include +#include + +#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 index 00000000..93c23fd2 --- /dev/null +++ b/skyrix-core/NGMime/NGImap4/imTimeMacros.h @@ -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 + +#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 index 00000000..86762c60 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGMime/NGMail/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..970022f8 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/ChangeLog @@ -0,0 +1,226 @@ +2004-07-22 Helge Hess + + * NGMBoxReader.m: fixed a gcc 3.4 warning (v4.2.170) + +2004-06-10 Helge Hess + + * NGMailAddressParser.m: added stronger typing for gcc 3.4 (v4.2.161) + +2004-06-09 Helge Hess + + * NGMailAddressParser.m: major code cleanups, cache YES number, cache + NSString class (v4.2.160) + +2004-02-10 Helge Hess + + * NGMBoxReader.m, NGPop3Client.m, NGSmtpClient.m: fixed compilation + warnings on OSX (v4.2.151) + +2004-02-08 Helge Hess + + * 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 + + * 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 + + * NGMimeMessageParser.m: code cleanups, fix a decode quoted printable + bug (sometimes last char was ignored) (v4.2.107) + +2003-04-09 Helge Hess + + * 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 + + * NGMimeMessageParser: add NGMimeRfc822BodyParser, + add delegate method bodyParserForPart: to call the + NGMimeRfc822BodyParser (v4.2.86) + +Mon Jan 27 19:13:34 2003 + + * NGMimeMessageGenerator.m: code cleanups, use disk blob handling from + NGMime (v4.2.73) + +Tue Jan 21 18:16:46 2003 + + * NGMimeMessageParser.m: increase version (NGMimePartParser got + new instance vars) (v4.2.70) + +2003-01-13 Helge Hess + + * NGMimeMessageParser.h: added some docu to header + +Mon Oct 21 16:15:58 2002 Jan Reichmann + + * NGMimeMessageParser.m: remove logs (v4.2.26) + +2002-08-15 Helge Hess + + * 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 + + * 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 + + * 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 + + * 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 + + * NGMailAddressParser.m: fixed address parsing bug + (delete white spaces between phrases) + +Thu Mar 14 15:05:53 2002 Jan41 Reichmann + + * NGMailAddressParser.m: fixed mail-address parsing bug + +Thu Nov 1 16:08:13 2001 Jan41 Reichmann + + * NGMimeMessageGenerator.m: fixed utf8 encoding bug + +Thu Oct 25 09:41:00 2001 Helge Hess + + * NGMimeMessageGenerator.m: fixed content-type access bug (use + -contentType method to access content types) + +Wed Oct 24 15:04:22 2001 Jan41 Reichmann + + * NGMimeMessageGenerator.m: add 8 bit Headerfield encoding default + +Wed Oct 24 12:54:58 2001 Helge Hess + + * updated to SKYRiXgreen version (mail address parser, message gen) + +Thu Oct 11 17:32:38 2001 Helge Hess + + * NGMimeMessage.m: make string-header safe + +Thu Aug 9 13:21:22 2001 Helge Hess + + * NGMBoxReader.m: use -initWithPath:, no use of NGFileUrl anymore + +Mon Apr 2 14:09:11 2001 Jan Reichmann + + * NGMailAddressParser.h: add doc + +Wed Mar 7 16:46:43 2001 Jan Reichmann + + * NGMimeMessage.m: fixed body == NSString bug + +Mon Mar 5 16:29:40 2001 Jan Reichmann + + * 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 + + * NGMimeMessageParser.m: fixed encoding bug + +Fri Jan 26 18:53:10 2001 Jan Reichmann + + * NGMimeMessageGenerator.m: fixed content bug + + * NGMailAddressParser.m: fixed outlock mail-address parse bug + +Tue Jun 6 17:39:08 2000 Jan Reichmann + + * NGMailAddressParser.[mh]: fixed type bug (char --> unsigned char) + + * NGMailAddressParser.m: fixed parse bug + +Tue May 30 15:25:41 2000 Jan Reichmann + + * NGMailAddressParser.m: add parseAddressList (addresses seperated + by comma) + +Tue Apr 25 15:29:35 2000 Jan Reichmann + + * 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 + + * MOF3 import + +Thu Sep 2 21:09:41 1999 Helge Hess + + * added class versions and superclass version checks + +Wed Aug 25 13:40:32 1999 Jan Reichmann + + * NGMimeMessageParser.m: L 93 fixed appendLC bug (set appendLC = NO) + +Thu Jul 22 14:28:12 1999 Jan Reichmann + + * NGMimeMessageGenerator.m (_base64Encoding): insert quoted-printable + encoding for text/* Mimeparts + +Fri Apr 16 18:00:50 1999 Helge Hess + + * mbox parser rewritten for better speed + +Mon Apr 12 16:47:33 1999 Helge Hess + + * use #include instead of #import, modified headers to support #include + +Fri Nov 27 15:37:04 1998 Helge Hess + + * started WIN32 port + +1998-10-09 Helge Hess + + * created ChangeLog + diff --git a/skyrix-core/NGMime/NGMail/GNUmakefile b/skyrix-core/NGMime/NGMail/GNUmakefile new file mode 100644 index 00000000..40aaf7c8 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/GNUmakefile @@ -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 index 00000000..9a0cdd5d --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMBoxReader.h @@ -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 + +#import +#import + +@class NSString, NSDictionary; + +@interface NGMBoxReader : NSEnumerator +{ +@protected + id source; + NSString *lastDate; + NSString *separator; + BOOL isEndOfStream; + + IMP readByte; +} + ++ (id)readerForMBox:(NSString *)_path; ++ (id)mboxWithSource:(id)_source; + +- (id)initWithSource:(id)_source; + +- (id)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 index 00000000..48ec796a --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMBoxReader.m @@ -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)_in { + return [[(NGMBoxReader *)[self alloc] initWithSource:_in] autorelease]; +} + +- (id)init { + return [self initWithSource:nil]; +} + +- (id)initWithSource:(id)_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)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 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 index 00000000..0b20bad3 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMail-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGMail + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGMail + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGMime/NGMail/NGMail.h b/skyrix-core/NGMime/NGMail/NGMail.h new file mode 100644 index 00000000..b6f336e4 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMail.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 index 00000000..f6c9f2ac --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMail.m @@ -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 +#import + +@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 index 00000000..d8a605c2 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddress.h @@ -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 + +@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 index 00000000..37773cb7 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddress.m @@ -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 index 00000000..bb1a8c18 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddressList.h @@ -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 + +@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 index 00000000..536bf63d --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddressList.m @@ -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 index 00000000..2a53ba5c --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddressParser.h @@ -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 + +@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 index 00000000..c93dfcb6 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailAddressParser.m @@ -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 index 00000000..41262cb6 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMailDecls.h @@ -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 index 00000000..5b51eadc --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessage.h @@ -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 +#include + +@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 index 00000000..02c0ba62 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessage.m @@ -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 index 00000000..1b937f22 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageBodyGenerator.m @@ -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)_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 index 00000000..bfc72111 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.h @@ -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 +#include + +/* + 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_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 index 00000000..6e4dcc2c --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageGenerator.m @@ -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_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)defaultBodyGenerator { + id gen; + + gen = [[NGMimeMessageBodyGenerator allocWithZone:[self zone]] init]; + [gen setUseMimeData:self->useMimeData]; + return gen; +} + +- (id)generatorForBodyOfPart:(id)_part { + id 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 index 00000000..cab7457c --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageMultipartBodyGenerator.m @@ -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)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen + generatorForPart:(id)_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 index 00000000..552a6092 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageParser.h @@ -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 + +/* + 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 index 00000000..f3c68b95 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageParser.m @@ -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)parser:(NGMimePartParser *)_parser + bodyParserForPart:(id)_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)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)_part data:(NSData *)_data + delegate:(id)_d +{ + id 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 index 00000000..2c995b22 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageRfc822BodyGenerator.m @@ -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)generatorForPart:(id)_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 index 00000000..e2489105 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGMimeMessageTextBodyGenerator.m @@ -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)_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 index 00000000..eb44ab78 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGPop3Client.h @@ -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 +#import +#import + +@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 socket; + NGBufferedStream *connection; + id text; + + NGPop3State state; + NGPop3Response *lastResponse; + BOOL isDebuggingEnabled; +} + ++ (id)pop3Client; +- (id)initWithSocket:(id)_socket; // designated initializer + +// accessors + +- (id)socket; +- (NGPop3State)state; +- (NGPop3Response *)lastResponse; + +- (void)setDebuggingEnabled:(BOOL)_flag; +- (BOOL)isDebuggingEnabled; + +// connection + +- (BOOL)connectToHost:(id)_host; +- (BOOL)connectToAddress:(id)_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 index 00000000..95aa514b --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGPop3Client.m @@ -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)_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)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)_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 \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 \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 \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:@"", + (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 index 00000000..1e7d5cdb --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGPop3Support.h @@ -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 +#include + +@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 + +@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 index 00000000..8b86b813 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGPop3Support.m @@ -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:@"", + (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:@"", + (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 index 00000000..061fd15a --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGSmtpClient.h @@ -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 +#import +#import + +@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 socket; + NGBufferedStream *connection; + id text; + + NGSmtpState state; + BOOL isDebuggingEnabled; + + struct { + BOOL hasExpand:1; + BOOL hasSize:1; + BOOL hasHelp:1; + BOOL hasPipelining; + } extensions; +} + ++ (id)smtpClient; +- (id)initWithSocket:(id)_socket; // designated initializer + +// accessors + +- (id)socket; +- (NGSmtpState)state; + +- (void)setDebuggingEnabled:(BOOL)_flag; +- (BOOL)isDebuggingEnabled; + +// connection + +- (BOOL)connectToHost:(id)_host; +- (BOOL)connectToAddress:(id)_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 index 00000000..115f6401 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGSmtpClient.m @@ -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)_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)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)_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:@"", + (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 index 00000000..8040e185 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGSmtpReplyCodes.h @@ -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 index 00000000..98638858 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGSmtpSupport.h @@ -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 +#include + +@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 index 00000000..0ce5846f --- /dev/null +++ b/skyrix-core/NGMime/NGMail/NGSmtpSupport.m @@ -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 = @" Service ready"; + break; + case NGSmtpServiceClosingChannel: // 221 + text = @" 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 "; + break; + + // 300 codes, positive intermediate reply + + case NGSmtpStartMailInput: // 354 + text = @"Start mail input; end with ."; + break; + + // 400 codes, transient negative completion reply + + case NGSmtpServiceNotAvailable: // 421 + text = @" 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 "; + 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:@"", _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:@"", + [self code], [self lastLine]]; +} + +@end /* NGSmtpResponse */ diff --git a/skyrix-core/NGMime/NGMail/README b/skyrix-core/NGMime/NGMail/README new file mode 100644 index 00000000..208d16b8 --- /dev/null +++ b/skyrix-core/NGMime/NGMail/README @@ -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 index 00000000..be6aba2d --- /dev/null +++ b/skyrix-core/NGMime/NGMail/common.h @@ -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 + +#include +#include +#include +#include + +#ifndef __MINGW32__ +# include +#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 index 00000000..1e1ff9eb --- /dev/null +++ b/skyrix-core/NGMime/NGMail/libNGMail.def @@ -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 index 00000000..29026be6 --- /dev/null +++ b/skyrix-core/NGMime/NGMime-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGMime + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGMime + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGMime/NGMime.h b/skyrix-core/NGMime/NGMime.h new file mode 100644 index 00000000..7c721b0b --- /dev/null +++ b/skyrix-core/NGMime/NGMime.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 index 00000000..bd97c4a4 --- /dev/null +++ b/skyrix-core/NGMime/NGMime.m @@ -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 index 00000000..e1aea78e --- /dev/null +++ b/skyrix-core/NGMime/NGMimeAddressHeaderFieldGenerator.m @@ -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 +#include +#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 index 00000000..fe0d3c9a --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyGenerator.h @@ -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 +#import +#import + +@class NSData, NSString, NSArray, NGMutableHashMap; +@class NGMimeMultipartBodyGenerator, NGMimeMultipartBody; + +@interface NGMimeBodyGenerator : NSObject +{ + BOOL useMimeData; +} +- (NSData *)generateBodyOfPart:(id)_part + additionalHeaders:(NGMutableHashMap *)_addHeaders + delegate:(id)_delegate; + +- (NSData *)encodeData:(NSData *)_data + forPart:(id)_part + additionalHeaders:(NGMutableHashMap *)_addHeaders; + +- (BOOL)useMimeData; +- (void)setUseMimeData:(BOOL)_b; +@end + +@interface NGMimeTextBodyGenerator : NGMimeBodyGenerator +@end + +@interface NGMimeRfc822BodyGenerator : NGMimeBodyGenerator + +- (id)generatorForPart:(id)_part; + +@end + +@interface NGMimeMultipartBodyGenerator : NGMimeBodyGenerator + ++ (NSString *)boundaryPrefix; + +- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen + prefixForPart:(id)_part + mimeMultipart:(NGMimeMultipartBody *)_body; + +- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen + suffixForPart:(id)_part + mimeMultipart:(NGMimeMultipartBody *)_body; + +- (id)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen + generatorForPart:(id)_part; + +- (NSData *)buildDataWithBoundary:(NSString *)_boundary + partsData:(NSArray *)_parts; + +- (NSString *)buildBoundaryForPart:(id)_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 index 00000000..c6050ae9 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyGenerator.m @@ -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 + +@implementation NGMimeBodyGenerator + ++ (int)version { + return 2; +} + +- (NSData *)generateBodyOfPart:(id)_part + additionalHeaders:(NGMutableHashMap *)_addHeaders + delegate:(id)_delegate +{ + return [self encodeData:[_part body] + forPart:_part + additionalHeaders:_addHeaders]; +} + +- (NSData *)encodeData:(NSData *)_data + forPart:(id)_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)_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)generatorForPart:(id)_part { + id g; + + g = [[[NGMimePartGenerator allocWithZone:[self zone]] init] + autorelease]; + [g setUseMimeData:self->useMimeData]; + return g; +} + +- (NSData *)generateBodyOfPart:(id)_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)_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)_part + additionalHeaders:(NGMutableHashMap *)_addHeaders + delegate:(id)_delegate +{ + // TODO: split up + NGMimeMultipartBody *body = nil; + NSMutableData *data = nil; + id tmp = nil; + NSArray *parts = nil; + id 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 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)_part + mimeMultipart:(NGMimeMultipartBody *)_body { + + return @""; // [_body prefix]; +} + +- (NSString *)multipartBodyGenerator:(NGMimeMultipartBodyGenerator *)_gen + suffixForPart:(id)_part + mimeMultipart:(NGMimeMultipartBody *)_body { + + return @""; //[_body suffix]; +} + +- (id)multipartBodyGenerator:(NGMimeBodyGenerator *)_gen + generatorForPart:(id)_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 index 00000000..70be6043 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyParser.h @@ -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 +#include + +@class NSData; + +@protocol NGMimeBodyParser < NSObject > + +- (id)parseBodyOfPart:(id)_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)_part + data:(NSData *)_data + delegate:(id)_d; + +- (id)parseBodyPartWithData:(NSData *)_rawData + inMultipart:(id)_multipart + parser:(NGMimePartParser *)_parser; // usually a NGMimeBodyPartParser + +@end + +@interface NSObject(NGMimeMultipartBodyParserDelegate) + +- (BOOL)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser + immediatlyParseBodyOfMultipart:(id)_part + data:(NSData *)_data; + +- (void)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser + foundPrefix:(NSData *)_prefix + inMultipart:(id)_part; + +- (void)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser + foundSuffix:(NSData *)_suffix + inMultipart:(id)_part; + +- (NGMimePartParser *)multipartBodyParser:(NGMimeMultipartBodyParser *)_parser + parserForEntity:(NSData *)_data + inMultipart:(id)_part; + +@end + +#endif /* __NGMime_NGMimeBodyParser_H__ */ diff --git a/skyrix-core/NGMime/NGMimeBodyParser.m b/skyrix-core/NGMime/NGMimeBodyParser.m new file mode 100644 index 00000000..34a3b5d1 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyParser.m @@ -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)_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)_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 index 00000000..ca6a40af --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyPart.h @@ -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 +#include + +@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 index 00000000..633ca779 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyPart.m @@ -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 + +@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 index 00000000..cd479154 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyPartParser.h @@ -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 + +/* + 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 index 00000000..8f5073c1 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeBodyPartParser.m @@ -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)_part { + return [NGMimeType mimeType:@"text/plain"]; +} + +- (id)producePartWithHeader:(NGHashMap *)_header { + return [NGMimeBodyPart bodyPartWithHeader:_header]; +} + +- (void)parseBodyOfPart:(id)_part { + [super parseBodyOfPart:_part]; +} + +@end /* NGMimeBodyPartParser */ diff --git a/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m new file mode 100644 index 00000000..c7421fb2 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m @@ -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 index 00000000..bd902ca1 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentDispositionHeaderFieldParser.m @@ -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 index 00000000..b8fcfc22 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldGenerator.m @@ -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 index 00000000..f3ce7a11 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentLengthHeaderFieldParser.m @@ -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: + @"", + (unsigned)self]; +} + +@end /* NGMimeContentLengthHeaderFieldParser */ diff --git a/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m b/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m new file mode 100644 index 00000000..6a2545db --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldGenerator.m @@ -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 index 00000000..11a4c6b9 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeContentTypeHeaderFieldParser.m @@ -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: + @"", + (unsigned)self]; +} + +@end /* NGMimeContentTypeHeaderFieldParser */ diff --git a/skyrix-core/NGMime/NGMimeDecls.h b/skyrix-core/NGMime/NGMimeDecls.h new file mode 100644 index 00000000..3eecb42d --- /dev/null +++ b/skyrix-core/NGMime/NGMimeDecls.h @@ -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 index 00000000..35487707 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeExceptions.h @@ -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 + +@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 index 00000000..4da4175e --- /dev/null +++ b/skyrix-core/NGMime/NGMimeExceptions.m @@ -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 index 00000000..1f92abf8 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeFileData.h @@ -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 + +@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 index 00000000..62150d96 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeFileData.m @@ -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 +#include +#include +#include + +@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 index 00000000..b2dfa6f7 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeGeneratorProtocols.h @@ -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 +#import + +@class NSData, NGMutableHashMap; + +@protocol NGMimePartGenerator + +/* generate mime from part and store it in _file */ +- (NSString *)generateMimeFromPartToFile:(id)_part; + +- (NSData *)generateMimeFromPart:(id)_part; +- (void)setDelegate:(id)_delegate; +- (id)delegate; +- (void)setUseMimeData:(BOOL)_useMimeData; + +@end + +@protocol NGMimeBodyGenerator < NSObject > + +- (NSData *)generateBodyOfPart:(id)_part + additionalHeaders:(NGMutableHashMap *)_addHeaders + delegate:(id)_delegate; + +- (NSData *)encodeData:(NSData *)_data + forPart:(id)_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 index 00000000..94d18946 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.h @@ -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 +#include + +@class NSString, NSData, NSMutableDictionary; + +@interface NGMimeHeaderFieldGenerator : NSObject + ++ (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 +{ +@protected + NSMutableDictionary *fieldNameToGenerate; + id defaultGenerator; +} + ++ (id)headerFieldGeneratorSet; ++ (id)defaultRfc822HeaderFieldGeneratorSet; + +- (id)init; +- (id)initWithDefaultGenerator:(id)_gen; + +/* accessors */ + +- (void)setGenerator:(id)_gen + forField:(NSString *)_name; + +- (void)setDefaultGenerator:(id)_gen; +- (id)_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 index 00000000..68a20243 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldGenerator.m @@ -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 index 00000000..87d4e300 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldGeneratorSet.m @@ -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)_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)_gen + forField:(NSString *)_name +{ + [self->fieldNameToGenerate setObject:_gen forKey:_name]; +} + +- (void)setDefaultGenerator:(id)_gen { + ASSIGN(self->defaultGenerator, _gen); +} + +- (id)_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 index 00000000..e4b191ec --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldParser.h @@ -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 + +@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 +{ +@protected + NSMutableDictionary *fieldNameToParser; + id defaultParser; +} + ++ (id)headerFieldParserSet; ++ (id)defaultRfc822HeaderFieldParserSet; +- (id)init; +- (id)initWithDefaultParser:(id)_parser; +- (id)initWithParseSet:(NGMimeHeaderFieldParserSet *)_set; + +/* accessors */ + +- (void)setParser:(id)_parser + forField:(NSString *)_name; + +- (void)setDefaultParser:(id)_parser; +- (id)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 index 00000000..3fb2d5ab --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldParser.m @@ -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 + +@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 index 00000000..cd159666 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFieldParserSet.m @@ -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 + +@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)_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)_parser + forField:(NSString *)_name { + + [self->fieldNameToParser setObject:_parser forKey:_name]; +} + +- (void)setDefaultParser:(id)_parser { + ASSIGN(self->defaultParser, _parser); +} +- (id)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: + @"", + (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 index 00000000..9bc9cf70 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFields.h @@ -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 +#include + +@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 index 00000000..e5a143c8 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeHeaderFields.m @@ -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 index 00000000..3cc6edb5 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeJoinedData.h @@ -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 + +@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 index 00000000..2c4623e4 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeJoinedData.m @@ -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 +#include +#include +#include +#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 index 00000000..ee3a32b6 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeMultipartBody.h @@ -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 +#include + +@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 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)_part; // designated initializer +- (id)initWithPart:(id)_part + data:(NSData *)_data + delegate:(id)_delegate; + +// accessors + +- (id)part; // the part the body belongs to + +- (NSArray *)parts; +- (void)addBodyPart:(id)_part; +- (void)addBodyPart:(id)_part atIndex:(int)_idx; +- (void)removeBodyPart:(id)_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 index 00000000..83a56a49 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeMultipartBody.m @@ -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)_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)_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)part { // the part the body belongs to + return self->part; +} + +- (NSArray *)parts { + return self->bodyParts; +} + +- (void)addBodyPart:(id)_part { + _checkArray(self); + [self->bodyParts addObject:_part]; +} +- (void)addBodyPart:(id)_part atIndex:(int)_idx { + _checkArray(self); + [self->bodyParts insertObject:_part atIndex:_idx]; +} + +- (void)removeBodyPart:(id)_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 index 00000000..ee75087a --- /dev/null +++ b/skyrix-core/NGMime/NGMimeMultipartBodyParser.m @@ -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)_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)parseBodyPartWithData:(NSData *)_rawData + inMultipart:(id)_multipart + parser:(NGMimePartParser *)_parser +{ + if (![_rawData length]) + return nil; + + return [_parser parsePartFromData:_rawData]; +} + +- (BOOL)parseBody:(NGMimeMultipartBody *)_body + ofMultipart:(id)_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)_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)_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 index 00000000..1917378f --- /dev/null +++ b/skyrix-core/NGMime/NGMimePartGenerator.h @@ -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 +#import +#import + +@class NSMutableData, NSData, NSString, NGHashMap, NGMutableHashMap; +@class NGMimeType, NGMimePartGenerator; + +@interface NGMimePartGenerator : NSObject +{ +@protected + NSMutableData *result; // result + id 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)_part; + + +/* generate mime from part and store it in the returned filename */ +- (NSString *)generateMimeFromPartToFile:(id)_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)_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)_part; + +/* returns header field generator for the specified field */ +- (id)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)generatorForBodyOfPart:(id)_part; + +/* ----- end hooks for subclasses ----- */ + +/* accessors */ +- (id)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)_gen + generateDataForHeaderField:(NSString *)_headerField + value:(NSEnumerator *)_value; + +/* + The delegate can choose, which generator should be used, to generate + the specified NGMimePart. +*/ +- (id)mimePartGenerator:(id)_gen + generatorForBodyOfPart:(id)_part; + +/* + The delegate has the opportunity to generate the whole body-part. Additional + headers like boundary can be set in _additionalHeaders. +*/ +- (NSData *)mimePartGenerator:(id)_gen + generateDataForBodyOfPart:(id)_part + additionalHeaders:(NGMutableHashMap *)_additionalHeaders; + +/* + The delegate can set prefix and suffix for a multipart. +*/ +- (NSString *)multipartBodyGenerator:(id)_bodyGen + prefixForPart:(id)_part; + +- (NSString *)multipartBodyGenerator:(id)_bodyGen + suffixForPart:(id)_part; + +/* + The delegate can select which NGMimeBodyGenerator should de used + for generate the given part. +*/ +- (id)multipartBodyGenerator:(id) + generatorForPart:(id)_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 index 00000000..64d97259 --- /dev/null +++ b/skyrix-core/NGMime/NGMimePartGenerator.m @@ -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 +#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)_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)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)_part { + return [NGMimeType mimeType:@"application/octet"]; +} + +- (id)defaultBodyGenerator { + id gen; + + gen = [[[NGMimeBodyGenerator alloc] init] autorelease]; + [(id)gen setUseMimeData:self->useMimeData]; + return gen; +} + +- (id)generatorForBodyOfPart:(id)_part { + id 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 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)_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)_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)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 index 00000000..c1e005f8 --- /dev/null +++ b/skyrix-core/NGMime/NGMimePartParser.h @@ -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 +#import +#import +#include +#include +#include + +/* + 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)parsePartFromStream:(id)_stream; +- (id)parsePartFromData:(NSData *)_data; + +/* header field parsing */ + +- (id)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 to abort the parsing process. +- (NGHashMap *)parseHeader; + +/* body parsing */ + +- (id)producePartWithHeader:(NGHashMap *)_header; + +- (NSData *)decodeBody:(NSData *)_data ofPart:(id)_part; + +- (id) + parserForBodyOfPart:(id)_part data:(NSData *)_dt; + +- (NGMimeType *)defaultContentTypeForPart:(id)_part; + +- (void)parseBodyOfPart:(id)_part; + +/* hooks for subclasses */ + +- (BOOL)parsePrefix; // returns NO to abort parsing +- (void)parseSuffix; +- (BOOL)prepareForParsingFromStream:(id)_stream; +- (void)finishParsingOfPart:(id)_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)_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)_part; + +/* + The parser successfully read in the body of the part. +*/ +- (void)parser:(NGMimePartParser *)_parser + didParseBodyOfPart:(id)_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)_part; + +/* + If the delegate does not parse the body itself, it can still select an + appropriate body parser using this method. +*/ +- (id)parser:(NGMimePartParser *)_parser + bodyParserForPart:(id)_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 index 00000000..53060d19 --- /dev/null +++ b/skyrix-core/NGMime/NGMimePartParser.m @@ -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)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 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)_part { + return (self->delegateRespondsTo.parserDecodeBodyOfPart) + ? [self->delegate parser:self decodeBody:_data ofPart:_part] + : _data; +} + +- (NGMimeType *)defaultContentTypeForPart:(id)_part { + static NGMimeType *octetType = nil; + + if (octetType == nil) + octetType = [[NGMimeType mimeType:@"application/octet-stream"] retain]; + return octetType; +} + +- (id)parserForBodyOfPart:(id)_p + data:(NSData *)_dt +{ + id ctype; + NGMimeType *contentType; + id 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)_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)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)_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)_part { + [self->source release]; self->source = nil; + self->contentLength = -1; + + self->la = NULL; + self->consume = NULL; + self->consumeCnt = NULL; +} + +- (void)finishParsingOfPartFromData:(id)_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)parsePart { + id 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)parsePartFromStream:(id)_stream { + id p; + + if (![self prepareForParsingFromStream:_stream]) + return nil; + + p = [self parsePart]; + [self finishParsingOfPart:p]; + return p; +} + +- (id)parsePartFromData:(NSData *)_data { + id 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 index 00000000..1269f9fb --- /dev/null +++ b/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldGenerator.m @@ -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 index 00000000..092213ef --- /dev/null +++ b/skyrix-core/NGMime/NGMimeRFC822DateHeaderFieldParser.m @@ -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 index 00000000..d0893220 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeStringHeaderFieldGenerator.m @@ -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 index 00000000..a9a4dd8a --- /dev/null +++ b/skyrix-core/NGMime/NGMimeStringHeaderFieldParser.m @@ -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: + @"", + (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 index 00000000..638c95f7 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeType.h @@ -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 +#import +#include + +@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 index 00000000..b57fe53b --- /dev/null +++ b/skyrix-core/NGMime/NGMimeType.m @@ -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, ¶meters)) { + 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:@"", [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 index 00000000..78c50890 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeUtilities.h @@ -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 +#import +#include + +// ******************** 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 index 00000000..57386e43 --- /dev/null +++ b/skyrix-core/NGMime/NGMimeUtilities.m @@ -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 +#include + +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 index 00000000..9c007e6f --- /dev/null +++ b/skyrix-core/NGMime/NGPart.h @@ -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 +#import + +/* + 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 index 00000000..7df1aca2 --- /dev/null +++ b/skyrix-core/NGMime/NGPart.m @@ -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 + +@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 index 00000000..22781266 --- /dev/null +++ b/skyrix-core/NGMime/NSCalendarDate+RFC822.m @@ -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 index 00000000..b4e6b1c4 --- /dev/null +++ b/skyrix-core/NGMime/README @@ -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 index 00000000..551b02db --- /dev/null +++ b/skyrix-core/NGMime/SxCore-NGMime.graffle @@ -0,0 +1,4824 @@ + + + + + CanvasColor + + w + 1.000000e+00 + + ColumnAlign + 0 + ColumnSpacing + 5.400000e+01 + GraphDocumentVersion + 2 + GraphicsList + + + Bounds + {{8.75, 730}, {109, 36}} + Class + ShapedGraphic + FitText + YES + ID + 163 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Bounds + {{548.75, 730}, {109, 36}} + Class + ShapedGraphic + FitText + YES + ID + 162 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Bounds + {{548.75, 10}, {109, 36}} + Class + ShapedGraphic + FitText + YES + ID + 161 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Bounds + {{8.75, 10}, {109, 36}} + Class + ShapedGraphic + FitText + YES + ID + 160 + Shape + Rectangle + Style + + fill + + Draws + NO + + shadow + + Draws + NO + + stroke + + Draws + NO + + + Text + + Text + {\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} + + + + Bounds + {{99, 1368}, {162, 18}} + Class + ShapedGraphic + ID + 159 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ResponseParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{819, 648}, {189, 18}} + Class + ShapedGraphic + ID + 134 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 648}, {198, 18}} + Class + ShapedGraphic + ID + 135 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 504}, {189, 18}} + Class + ShapedGraphic + ID + 136 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 621}, {198, 18}} + Class + ShapedGraphic + ID + 137 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 594}, {198, 18}} + Class + ShapedGraphic + ID + 138 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 477}, {189, 18}} + Class + ShapedGraphic + ID + 139 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 594}, {189, 18}} + Class + ShapedGraphic + ID + 140 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 450}, {189, 18}} + Class + ShapedGraphic + ID + 141 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 495}, {189, 18}} + Class + ShapedGraphic + ID + 142 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{711, 387}, {189, 18}} + Class + ShapedGraphic + ID + 143 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 450}, {189, 18}} + Class + ShapedGraphic + ID + 144 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{711, 549}, {189, 18}} + Class + ShapedGraphic + ID + 145 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 621}, {189, 18}} + Class + ShapedGraphic + ID + 146 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGConcreteMimeType.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 134 + + ID + 147 + Points + + {815.318, 567} + {903.682, 648} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + Class + LineGraphic + Head + + ID + 135 + + ID + 148 + Points + + {796.091, 567} + {711.409, 648} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + Class + LineGraphic + Head + + ID + 136 + + ID + 149 + Points + + {813.808, 405} + {905.192, 504} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 143 + + + + Class + LineGraphic + Head + + ID + 137 + + ID + 150 + Points + + {792.562, 567} + {714.938, 621} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + Class + LineGraphic + Head + + ID + 138 + + ID + 151 + Points + + {784.8, 567} + {722.7, 594} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + Class + LineGraphic + Head + + ID + 139 + + ID + 152 + Points + + {816.3, 405} + {902.7, 477} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 143 + + + + Class + LineGraphic + Head + + ID + 140 + + ID + 153 + Points + + {827.1, 567} + {891.9, 594} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + Class + LineGraphic + Head + + ID + 141 + + ID + 154 + Points + + {790.071, 405} + {712.929, 450} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 143 + + + + Class + LineGraphic + Head + + ID + 145 + + ID + 155 + Points + + {805.5, 405} + {805.5, 549} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 143 + + + + Class + LineGraphic + Head + + ID + 142 + + ID + 156 + Points + + {697.5, 468} + {697.5, 495} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 141 + + + + Class + LineGraphic + Head + + ID + 144 + + ID + 157 + Points + + {820.929, 405} + {898.071, 450} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 143 + + + + Class + LineGraphic + Head + + ID + 146 + + ID + 158 + Points + + {819, 567} + {900, 621} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 145 + + + + ID + 133 + + + Bounds + {{63, 495}, {126, 18}} + Class + ShapedGraphic + ID + 132 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessage.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1341}, {162, 18}} + Class + ShapedGraphic + ID + 131 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{756, 1341}, {243, 18}} + Class + ShapedGraphic + ID + 118 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{783, 1251}, {189, 18}} + Class + ShapedGraphic + ID + 119 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{666, 1314}, {243, 18}} + Class + ShapedGraphic + ID + 120 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{693, 1224}, {189, 18}} + Class + ShapedGraphic + ID + 121 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{864, 1188}, {189, 18}} + Class + ShapedGraphic + ID + 122 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{900, 1152}, {153, 18}} + Class + ShapedGraphic + ID + 123 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{585, 1287}, {243, 18}} + Class + ShapedGraphic + ID + 124 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{612, 1197}, {189, 18}} + Class + ShapedGraphic + ID + 125 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{720, 1152}, {153, 18}} + Class + ShapedGraphic + ID + 126 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 118 + + ID + 127 + Points + + {877.5, 1269} + {877.5, 1341} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 119 + + + + Class + LineGraphic + Head + + ID + 119 + + ID + 128 + Points + + {803.864, 1170} + {870.136, 1251} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 126 + + + + Class + LineGraphic + Head + + ID + 122 + + ID + 129 + Points + + {837, 1170} + {918, 1188} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 126 + + + + Class + LineGraphic + Head + + ID + 126 + + ID + 130 + Points + + {900, 1161} + {873, 1161} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 123 + + + + ID + 117 + + + Class + Group + Graphics + + + Bounds + {{99, 1017}, {153, 18}} + Class + ShapedGraphic + ID + 112 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + Rectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{288, 1053}, {153, 18}} + Class + ShapedGraphic + ID + 113 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4FileManager.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{288, 1017}, {153, 18}} + Class + ShapedGraphic + ID + 114 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileManager.h + + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 114 + + ID + 115 + Points + + {252, 1026} + {288, 1026} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 112 + + + + Class + LineGraphic + Head + + ID + 113 + + ID + 116 + Points + + {364.5, 1035} + {364.5, 1053} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 114 + + + + ID + 111 + + + Bounds + {{801, 1035}, {252, 18}} + Class + ShapedGraphic + ID + 110 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{855, 36}, {126, 18}} + Class + ShapedGraphic + ID + 101 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{630, 72}, {171, 18}} + Class + ShapedGraphic + ID + 102 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{810, 72}, {171, 18}} + Class + ShapedGraphic + ID + 103 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{702, 36}, {135, 18}} + Class + ShapedGraphic + ID + 104 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{684, 108}, {171, 18}} + Class + ShapedGraphic + ID + 105 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 104 + + ID + 106 + Points + + {855, 45} + {837, 45} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 101 + + + + Class + LineGraphic + Head + + ID + 102 + + ID + 107 + Points + + {756, 54} + {729, 72} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 104 + + + + Class + LineGraphic + Head + + ID + 103 + + ID + 108 + Points + + {801, 54} + {864, 72} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 104 + + + + Class + LineGraphic + Head + + ID + 105 + + ID + 109 + Points + + {769.5, 54} + {769.5, 108} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 104 + + + + ID + 100 + + + Bounds + {{558, 1008}, {279, 18}} + Class + ShapedGraphic + ID + 99 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1314}, {162, 18}} + Class + ShapedGraphic + ID + 98 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Client.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{846, 801}, {207, 18}} + Class + ShapedGraphic + ID + 97 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1287}, {162, 18}} + Class + ShapedGraphic + ID + 96 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGSmtpClient.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1260}, {162, 18}} + Class + ShapedGraphic + ID + 95 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGSmtpSupport.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{801, 981}, {252, 18}} + Class + ShapedGraphic + ID + 94 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{63, 450}, {126, 18}} + Class + ShapedGraphic + ID + 93 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGPart.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{198, 495}, {126, 18}} + Class + ShapedGraphic + ID + 92 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyPart.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{225, 666}, {162, 18}} + Class + ShapedGraphic + ID + 91 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{585, 207}, {126, 18}} + Class + ShapedGraphic + ID + 73 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{576, 243}, {144, 18}} + Class + ShapedGraphic + ID + 74 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{900, 207}, {126, 18}} + Class + ShapedGraphic + ID + 75 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{882, 243}, {162, 18}} + Class + ShapedGraphic + ID + 76 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{819, 324}, {180, 18}} + Class + ShapedGraphic + ID + 77 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{846, 288}, {180, 18}} + Class + ShapedGraphic + ID + 78 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{621, 324}, {180, 18}} + Class + ShapedGraphic + ID + 79 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{594, 288}, {180, 18}} + Class + ShapedGraphic + ID + 80 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{747, 162}, {126, 18}} + Class + ShapedGraphic + ID + 81 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{747, 207}, {126, 18}} + Class + ShapedGraphic + ID + 82 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 75 + + ID + 83 + Points + + {840.6, 180} + {932.4, 207} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 81 + + + + Class + LineGraphic + Head + + ID + 73 + + ID + 84 + Points + + {777.6, 180} + {680.4, 207} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 81 + + + + Class + LineGraphic + Head + + ID + 76 + + ID + 85 + Points + + {963, 225} + {963, 243} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 75 + + + + Class + LineGraphic + Head + + ID + 77 + + ID + 86 + Points + + {817.615, 225} + {901.385, 324} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 82 + + + + Class + LineGraphic + Head + + ID + 78 + + ID + 87 + Points + + {824, 225} + {922, 288} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 82 + + + + Class + LineGraphic + Head + + ID + 79 + + ID + 88 + Points + + {802.385, 225} + {718.615, 324} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 82 + + + + Class + LineGraphic + Head + + ID + 80 + + ID + 89 + Points + + {796, 225} + {698, 288} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 82 + + + + Class + LineGraphic + Head + + ID + 82 + + ID + 90 + Points + + {810, 180} + {810, 207} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 81 + + + + ID + 72 + + + Class + Group + Graphics + + + Bounds + {{45, 963}, {261, 18}} + Class + ShapedGraphic + ID + 60 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{243, 936}, {243, 18}} + Class + ShapedGraphic + ID + 61 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{126, 774}, {180, 18}} + Class + ShapedGraphic + ID + 62 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{324, 774}, {162, 18}} + Class + ShapedGraphic + ID + 63 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{45, 909}, {261, 18}} + Class + ShapedGraphic + ID + 64 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{243, 882}, {243, 18}} + Class + ShapedGraphic + ID + 65 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{126, 810}, {180, 18}} + Class + ShapedGraphic + ID + 66 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 855}, {261, 18}} + Class + ShapedGraphic + ID + 67 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 61 + + ID + 68 + Points + + {226.607, 828} + {353.893, 936} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 66 + + + + Class + LineGraphic + Head + + ID + 62 + + ID + 69 + Points + + {324, 783} + {306, 783} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 63 + + + + Class + LineGraphic + Head + + ID + 66 + + ID + 70 + Points + + {357.75, 792} + {263.25, 810} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 63 + + + + Class + LineGraphic + Head + + ID + 65 + + ID + 71 + Points + + {234.562, 828} + {345.938, 882} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 66 + + + + ID + 59 + + + Bounds + {{99, 1233}, {162, 18}} + Class + ShapedGraphic + ID + 58 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeMultipartBody.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{207, 405}, {144, 18}} + Class + ShapedGraphic + ID + 57 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeBodyPartParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{54, 306}, {180, 18}} + Class + ShapedGraphic + ID + 56 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{288, 72}, {171, 18}} + Class + ShapedGraphic + ID + 55 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGExtensions/NGFileFolderInfoDataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1206}, {162, 18}} + Class + ShapedGraphic + ID + 54 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddressList.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1179}, {162, 18}} + Class + ShapedGraphic + ID + 53 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddressParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{126, 360}, {144, 18}} + Class + ShapedGraphic + ID + 52 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimePartParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{54, 405}, {144, 18}} + Class + ShapedGraphic + ID + 51 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMimeMessageParser.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{558, 954}, {279, 18}} + Class + ShapedGraphic + ID + 50 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{90, 72}, {171, 18}} + Class + ShapedGraphic + ID + 49 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4DataSource.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{801, 927}, {252, 18}} + Class + ShapedGraphic + ID + 48 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1152}, {162, 18}} + Class + ShapedGraphic + ID + 47 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMailAddress.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{198, 567}, {126, 18}} + Class + ShapedGraphic + ID + 46 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Folder.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 1125}, {162, 18}} + Class + ShapedGraphic + ID + 45 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Message.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{558, 1080}, {279, 18}} + Class + ShapedGraphic + ID + 44 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFields.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{243, 306}, {180, 18}} + Class + ShapedGraphic + ID + 43 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGMBoxReader.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{288, 1152}, {162, 18}} + Class + ShapedGraphic + ID + 42 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Client.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{144, 270}, {180, 18}} + Class + ShapedGraphic + ID + 41 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{288, 1125}, {162, 18}} + Class + ShapedGraphic + ID + 40 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMail/NGPop3Support.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{63, 531}, {126, 18}} + Class + ShapedGraphic + ID + 39 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{63, 567}, {126, 18}} + Class + ShapedGraphic + ID + 38 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4ServerRoot.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{720, 756}, {189, 18}} + Class + ShapedGraphic + ID + 37 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{54, 144}, {180, 18}} + Class + ShapedGraphic + ID + 36 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Support.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{54, 180}, {180, 18}} + Class + ShapedGraphic + ID + 35 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGImap4/NGImap4Context.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{63, 630}, {135, 18}} + Class + ShapedGraphic + ID + 34 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeGeneratorProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{225, 630}, {162, 18}} + Class + ShapedGraphic + ID + 33 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimePartGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{711, 846}, {207, 18}} + Class + ShapedGraphic + ID + 32 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{558, 900}, {279, 18}} + Class + ShapedGraphic + ID + 31 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGMime/NGMimeHeaderFieldGenerator.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{189, 36}, {171, 18}} + Class + ShapedGraphic + ID + 30 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/EOControl/EODataSource.h + + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 132 + + ID + 29 + Points + + {126, 468} + {126, 495} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 93 + + + + Class + LineGraphic + Head + + ID + 110 + + ID + 28 + Points + + {819.857, 864} + {921.643, 1035} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + Class + LineGraphic + Head + + ID + 99 + + ID + 27 + Points + + {808, 864} + {704, 1008} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + Class + LineGraphic + Head + + ID + 97 + + ID + 26 + Points + + {841.5, 774} + {922.5, 801} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 37 + + + + Class + LineGraphic + Head + + ID + 94 + + ID + 25 + Points + + {822, 864} + {919.5, 981} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + Class + LineGraphic + Head + + ID + 92 + + ID + 24 + Points + + {153, 468} + {234, 495} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 93 + + + + Class + LineGraphic + Head + + ID + 120 + + ID + 23 + Points + + {787.5, 1242} + {787.5, 1314} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 121 + + + + Class + LineGraphic + Head + + ID + 91 + + ID + 22 + Points + + {306, 648} + {306, 666} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 33 + + + + Class + LineGraphic + Head + + ID + 74 + + ID + 21 + Points + + {648, 225} + {648, 243} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 73 + + + + Class + LineGraphic + Head + + ID + 60 + + ID + 20 + Points + + {213.618, 828} + {177.882, 963} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 66 + + + + Class + LineGraphic + Head + + ID + 57 + + ID + 19 + Points + + {214.2, 378} + {262.8, 405} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 52 + + + + Class + LineGraphic + Head + + ID + 56 + + ID + 18 + Points + + {211.5, 288} + {166.5, 306} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 41 + + + + Class + LineGraphic + Head + + ID + 55 + + ID + 17 + Points + + {299.25, 54} + {348.75, 72} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 30 + + + + Class + LineGraphic + Head + + ID + 51 + + ID + 16 + Points + + {183.6, 378} + {140.4, 405} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 52 + + + + Class + LineGraphic + Head + + ID + 50 + + ID + 15 + Points + + {804.75, 864} + {707.25, 954} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + Class + LineGraphic + Head + + ID + 49 + + ID + 14 + Points + + {249.75, 54} + {200.25, 72} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 30 + + + + Class + LineGraphic + Head + + ID + 121 + + ID + 13 + Points + + {795.375, 1170} + {788.625, 1224} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 126 + + + + Class + LineGraphic + Head + + ID + 64 + + ID + 12 + Points + + {212.318, 828} + {179.182, 909} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 66 + + + + Class + LineGraphic + Head + + ID + 48 + + ID + 11 + Points + + {827, 864} + {914.5, 927} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + Class + LineGraphic + Head + + ID + 46 + + ID + 10 + Points + + {159.75, 549} + {227.25, 567} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 39 + + + + Class + LineGraphic + Head + + ID + 124 + + ID + 9 + Points + + {706.5, 1215} + {706.5, 1287} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 125 + + + + Class + LineGraphic + Head + + ID + 43 + + ID + 8 + Points + + {258.75, 288} + {308.25, 306} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 41 + + + + Class + LineGraphic + Head + + ID + 125 + + ID + 7 + Points + + {778.5, 1170} + {724.5, 1197} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 126 + + + + Class + LineGraphic + Head + + ID + 38 + + ID + 6 + Points + + {126, 549} + {126, 567} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 39 + + + + Class + LineGraphic + Head + + ID + 32 + + ID + 5 + Points + + {814.5, 774} + {814.5, 846} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 37 + + + + Class + LineGraphic + Head + + ID + 35 + + ID + 4 + Points + + {144, 162} + {144, 180} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 36 + + + + Class + LineGraphic + Head + + ID + 33 + + ID + 3 + Points + + {198, 639} + {225, 639} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 34 + + + + Class + LineGraphic + Head + + ID + 67 + + ID + 2 + Points + + {207.9, 828} + {183.6, 855} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 66 + + + + Class + LineGraphic + Head + + ID + 31 + + ID + 1 + Points + + {795, 864} + {717, 900} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 32 + + + + GridInfo + + HPages + 2 + ImageCounter + 1 + IsPalette + NO + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + AutoAdjust + YES + HierarchicalOrientation + 0 + MagneticFieldCenter + {0, 0} + + MagnetsEnabled + YES + PageBreakColor + + w + 3.333333e-01 + + PageBreaks + YES + PageSetup + + BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE + hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpFZKEhIQITlNT + dHJpbmcBlIQBKw9OU1BhZ2VzUGVyU2hlZXSGkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVl + AJSEASqEhAFznQGGkoSZmRBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29s + Sm9ihpKEmZkOTlNCb3R0b21NYXJnaW6GkoSbnISEAWaeJIaShJmZC05TUGFwZXJOYW1l + hpKEmZkCQTSGkoSZmQ9OU1ByaW50QWxsUGFnZXOGkoSbnJ2dAIaShJmZDU5TSm9iRmVh + dHVyZXOGkoSWlwCGkoSZmQ1OU1JpZ2h0TWFyZ2luhpKEm5yiniSGkoSZmQhOU0NvcGll + c4aShJuchIQBU58BhpKEmZkPTlNTY2FsaW5nRmFjdG9yhpKEm5yEhAFkoAGGkoSZmQtO + U0ZpcnN0UGFnZYaShJucrZ8BhpKEmZkUTlNWZXJ0aWNhbFBhZ2luYXRpb26GkoSbnJ2d + AIaShJmZEk5TUmV2ZXJzZVBhZ2VPcmRlcoaShJuchIQBY6EAhpKEmZkVTlNIb3Jpem9u + YWxQYWdpbmF0aW9uhpKEm5ydnQCGkoSZmRZOU0hvcml6b250YWxseUNlbnRlcmVkhpKE + m5ydnQGGkoSZmQxOU0xlZnRNYXJnaW6GkoSbnKKeJIaShJmZDU5TT3JpZW50YXRpb26G + koSbnJ2dAIaShJmZGU5TUHJpbnRSZXZlcnNlT3JpZW50YXRpb26GkraShJmZCk5TTGFz + dFBhZ2WGkoSbnISXl4J/////hpKEmZkLTlNUb3BNYXJnaW6GkoSbnKKeJIaShJmZFE5T + VmVydGljYWxseUNlbnRlcmVkhpK7koSZmQtOU1BhcGVyU2l6ZYaShJychIQMe19OU1Np + emU9ZmZ9ooECU4EDSoaGhg== + + RowAlign + 0 + RowSpacing + 9.000000e+00 + VPages + 2 + WindowInfo + + Frame + {{83, 91}, {566, 801}} + VisibleRegion + {{-24, 0}, {1102, 1448}} + Zoom + 0.5 + + + diff --git a/skyrix-core/NGMime/TODO b/skyrix-core/NGMime/TODO new file mode 100644 index 00000000..8230a609 --- /dev/null +++ b/skyrix-core/NGMime/TODO @@ -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 index 00000000..d9e65d0b --- /dev/null +++ b/skyrix-core/NGMime/Version @@ -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 index 00000000..192cead1 --- /dev/null +++ b/skyrix-core/NGMime/common.h @@ -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 + +#if LIB_FOUNDATION_LIBRARY +# import +#elif NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY +# import +# import +#endif + +#include +#include + +#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 index 00000000..30086d3d --- /dev/null +++ b/skyrix-core/NGMime/libNGMime.def @@ -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 index 00000000..c315aac3 --- /dev/null +++ b/skyrix-core/NGMime/timeMacros.h @@ -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 + +#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 index 00000000..fff156f5 --- /dev/null +++ b/skyrix-core/NGStreams/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGStreams/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-core/NGStreams/COPYRIGHT @@ -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 index 00000000..afb67e94 --- /dev/null +++ b/skyrix-core/NGStreams/ChangeLog @@ -0,0 +1,368 @@ +2004-07-22 Helge Hess + + * NGLocalSocketAddress.m: fixed a gcc 3.4 warning (v4.2.41) + +2004-07-05 Helge Hess + + * GNUmakefile.preamble: added missing library lookup path to EOControl, + this fixes OGo bug #820 (v4.2.40) + +2004-06-09 Helge Hess + + * GNUmakefile.preamble: added prebinding (v4.2.39) + +2004-05-05 Marcus Mueller + + * 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 + + * GNUmakefile.preamble: define OPENSSL_NO_KRB5 to keep Fedora and RH9 + happy on compilation (v4.2.37) + +2004-02-11 Helge Hess + + * 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 + + * NGCTextStream.m, NGConcreteStreamFileHandle.m, NGFilterStream.m, + NGFilterTextStream.m: fixed minor compilation warnings on OSX + (v4.2.35) + +2004-01-25 Helge Hess + + * 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 + + * 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 + + * NGDataStream.m: properly return last-exception (always returned + nil!) - could have side-effects (v4.2.32) + +2004-01-12 Helge Hess + + * NGDataStream.m: subminor cleanups (v4.2.31) + +2003-11-30 Helge Hess + + * configure.in: patched to use GNUSTEP_MAKEFILES (as suggested by + chunsj@embian.com) (v4.2.30) + +2003-11-09 Helge Hess + + * NGActiveSocket.m, NGFilterStream.m, NGStreamCoder.m: minor tweaks + for MacOSX (v4.2.29) + +2003-10-13 Helge Hess + + * 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 + + * NGLocalSocketAddress.m, NGLocalSocketDomain.m: + include if __FreeBSD__ is defined. This will + currently affect FreeBSD 4.x only. (v4.2.27) + +2003-09-06 Helge Hess + + * various fixes to warnings on MacOSX (v4.2.26) + +2003-09-06 Marcus Mueller + + * configure.in: truncate target_os to "freebsd" on FreeBSD + +2003-09-01 Helge Hess + + * 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 + + * small cleanups to the included headers to improve gstep-base + compatibility (v4.2.24) + +2003-07-20 Helge Hess + + * NGGZipStream.m: removed dependency on zutil.h (v4.2.23) + +2003-05-26 Helge Hess + + * updated MacOSX support, removed dependencies on FoundationExt + (v4.2.22) + +2003-05-15 Helge Hess + + * NGByteBuffer.m: fixed the last signed/unsigned warnings, smaller + cleanups to -la: (v4.2.21) + +2003-05-14 Helge Hess + + * 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 + + * NGSocket.m: allocate sockets in the NGInternetSocketDomain by default + (v4.2.19) + +2003-01-20 Helge Hess + + * replaced some RETAIN macros (v4.2.18) + +2003-01-14 Helge Hess + + * NGPassiveSocket.m, NGInternetSocketDomain.m: small code cleanups + (v4.2.17) + +2003-01-07 Helge Hess + + * 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 + + * 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 + + * 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 + + * NGDescriptorFunctions.m: added some debugging/logging (new default + NGLogDescriptorRecv) (v4.2.13) + +2002-09-30 Helge Hess + + * 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 + + * 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 + + * v4.2.10 + + * NGBase64Stream.m, NGConcreteStreamFileHandle.m, NGStream.m: + fixed 'char-buffer in Exception Handler scope' bug + +2002-08-28 Helge Hess + + * some tweaks to support OSX Jaguar (v4.2.9) + +2002-08-15 Helge Hess + + * NGFileStream.m: do not log, if the filestream is closed on + deallocation (v4.2.8) + +Wed Aug 14 09:49:05 2002 Bjoern Stierand + + * NGNetUtilities.m (NGSocketAddressFromString): allows definition + of kernel bound addresses using 'host:auto' or '*:auto' + (v4.2.7) + +2002-07-08 Helge Hess + + * 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 + + * NGLocalSocketAddress.h: small fix for MacOSX + +Fri May 31 16:08:56 2002 Jan41 Reichmann + + * 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 + + * 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 + + * added NGGZipStream from NGZlib + +Mon Apr 29 13:46:11 2002 Helge Hess + + * NGByteBuffer.m: modified to support the new exception-less IO ... + +Tue Apr 23 12:32:23 2002 Helge Hess + + * NGActiveSocket.m: do not throw exception if connect failed (rather + set the last exception ...) + +Thu Mar 14 13:39:10 2002 Helge Hess + + * 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 + + * 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 + + * NGActiveSocket.m: throws less exceptions (uses -lastException,retval) + +Mon Feb 25 18:43:13 2002 Helge Hess + + * NGBufferedStream.m: checks return codes + +Thu Feb 21 12:04:16 2002 Helge Hess + + * NGStreamExceptions.m: added -raiseOnStream:... + +Wed Feb 20 13:30:44 2002 Helge Hess + + * everything reworked not to throw exceptions ... + +Fri Dec 7 14:35:47 2001 Jan41 Reichmann + + * NGByteBuffer.m: add profiling + +Mon Oct 8 17:47:01 2001 Helge Hess + + * 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 + + * NGInternetSocketAddress.m: fixed recursion bug + +Thu Aug 9 14:14:17 2001 Helge Hess + + * removed all NGUrl related stuff + +Thu Aug 9 14:00:04 2001 Helge Hess + + * moved URL escaping to NGExtensions + + * NGFileStream.m: added -initWithPath: + +Tue May 15 19:05:45 2001 Helge Hess + + * NGActiveSocket.m: added max-retry count (20) for writeBytes: with + errno==0 + +Wed May 9 19:22:43 2001 Joerg Grimm + + * NGActiveSocket.m: check for errno=0 if writeResult<0 + +Mon Feb 26 11:13:12 2001 Helge Hess + + * NGActiveSocket.m: added more errno=0-on-fail checking + +Fri Feb 23 21:40:40 2001 Helge Hess + + * 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 + + * NGUrl.m: modified URL encoding/decoding stuff to use unsigned char + +Mon Sep 18 10:47:41 2000 Helge Hess + + * NGCTextStream.m: fixed bug in -writeString + +Tue Jun 13 19:40:41 2000 Helge Hess + + * NGUrl.m, NGFileUrl.m: doesn't use stack-based buffers anymore + +Fri Jun 9 17:38:27 2000 Helge Hess + + * GNUmakefile: added -Wall + +Tue Feb 29 17:08:45 2000 Helge Hess + + * MOF3 import + diff --git a/skyrix-core/NGStreams/DESIGN b/skyrix-core/NGStreams/DESIGN new file mode 100644 index 00000000..49c8689f --- /dev/null +++ b/skyrix-core/NGStreams/DESIGN @@ -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 index 00000000..372fba42 --- /dev/null +++ b/skyrix-core/NGStreams/GNUmakefile @@ -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 index 00000000..0ec647d2 --- /dev/null +++ b/skyrix-core/NGStreams/GNUmakefile.postamble @@ -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 index 00000000..f9a9e45c --- /dev/null +++ b/skyrix-core/NGStreams/GNUmakefile.preamble @@ -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 index 00000000..14930dc5 --- /dev/null +++ b/skyrix-core/NGStreams/NGActiveSSLSocket.m @@ -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 +#include "common.h" + +#if HAVE_OPENSSL +# define id openssl_id +# include +# undef id +#endif + +@interface NGActiveSocket(UsedPrivates) +- (BOOL)primaryConnectToAddress:(id)_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)_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)_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)_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 index 00000000..eb073afc --- /dev/null +++ b/skyrix-core/NGStreams/NGActiveSocket+serialization.m @@ -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)_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)_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 index 00000000..5e233522 --- /dev/null +++ b/skyrix-core/NGStreams/NGActiveSocket.m @@ -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 +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif +#if defined(HAVE_TIME_H) || defined(__APPLE__) +# include +#endif +#if defined(HAVE_SYS_TIME_H) || defined(__APPLE__) +# include +#endif +#if defined(HAVE_FCNTL_H) || defined(__APPLE__) +# include +#endif + +#if defined(__APPLE__) +# include +# include +# include +#endif + +#if HAVE_WINDOWS_H && !defined(__CYGWIN32__) +# include +#endif + +#if defined(WIN32) && !defined(__CYGWIN32__) +# include +# define ioctl ioctlsocket +#endif + +#include "common.h" + +#include +#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)_local + remoteAddress:(id)_remote; + +@end + +@implementation NGActiveSocket + +#if !defined(WIN32) || defined(__CYGWIN32__) + ++ (BOOL)socketPair:(id[2])_pair inDomain:(id)_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)_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)_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)_local + remoteAddress:(id)_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)_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)_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)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 = @""; + + switch ([self mode]) { + case NGStreamMode_undefined: result = @""; 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 + +@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 index 00000000..782734ee --- /dev/null +++ b/skyrix-core/NGStreams/NGBase64Stream.m @@ -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 index 00000000..ad05d64a --- /dev/null +++ b/skyrix-core/NGStreams/NGBufferedStream.m @@ -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)_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)_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)_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)_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)_source { + return [self initWithSource:_source bufferSize:DEFAULT_BUFFER_SIZE]; +} +- (id)initWithInputSource:(id)_source { + return [self initWithInputSource:_source bufferSize:DEFAULT_BUFFER_SIZE]; +} +- (id)initWithOutputSource:(id)_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 index 00000000..bec356a1 --- /dev/null +++ b/skyrix-core/NGStreams/NGByteBuffer.m @@ -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 + +#if LIB_FOUNDATION_LIBRARY +# include +#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)_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)_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)_source { + [self release]; + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (id)initWithInputSource:(id)_source { + [self release]; + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (id)initWithOutputSource:(id)_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] : 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 index 00000000..23df212c --- /dev/null +++ b/skyrix-core/NGStreams/NGByteCountStream.m @@ -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)_stream byte:(unsigned char)_byte { + return [[[self alloc] initWithSource:_stream byte:_byte] autorelease]; +} + +- (id)initWithSource:(id)_source byte:(unsigned char)_byte { + if ((self = [super initWithSource:_source])) { + [self setByteToCount:_byte]; + } + return self; +} +- (id)initWithSource:(id)_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 index 00000000..6afe8fb1 --- /dev/null +++ b/skyrix-core/NGStreams/NGCTextStream.m @@ -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 +#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 NGTextIn = nil; +NGStreams_DECLARE id NGTextOut = nil; +NGStreams_DECLARE id 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)NGIn]; + NGTextOut = [(NGCTextStream *)[NGCTextStream alloc] + initWithSource:(id)NGOut]; + NGTextErr = [(NGCTextStream *)[NGCTextStream alloc] + initWithSource:(id)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)_s { + if (_s == nil) return nil; + return [[(NGCTextStream *)[self alloc] initWithInputSource:_s] autorelease]; +} ++ (id)textStreamWithOutputSource:(id)_s { + if (_s == nil) return nil; + return [[(NGCTextStream *)[self alloc] initWithOutputSource:_s] autorelease]; +} ++ (id)textStreamWithSource:(id)_stream { + if (_stream == nil) return nil; + return [[(NGCTextStream *)[self alloc] initWithSource:_stream] autorelease]; +} + +- (id)initWithSource:(id)_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)_source { + return [self initWithSource:(id)_source]; +} +- (id)initWithOutputSource:(id)_source { + return [self initWithSource:(id)_source]; +} + +- (void)dealloc { + [self->source release]; + self->readBytes = NULL; + self->writeBytes = NULL; + self->flushBuffer = NULL; + [super dealloc]; +} + +/* accessors */ + +- (id)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 index 00000000..6db00234 --- /dev/null +++ b/skyrix-core/NGStreams/NGCharBuffer.m @@ -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 +#endif + +typedef struct NGCharBufferLA { + unichar character; + char isEOF:1; + char isFetched:1; +} LA_NGCharBuffer; + +@implementation NGCharBuffer + ++ (id)charBufferWithSource:(id)_source la:(int)_la { + return [[[self alloc] initWithSource:_source la:_la] autorelease]; +} + +- (id)initWithSource:(id)_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)_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 index 00000000..90430f07 --- /dev/null +++ b/skyrix-core/NGStreams/NGConcreteStreamFileHandle.m @@ -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 +#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)_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)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)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 index 00000000..6b6032e8 --- /dev/null +++ b/skyrix-core/NGStreams/NGDataStream.m @@ -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 index 00000000..2f5a53e4 --- /dev/null +++ b/skyrix-core/NGStreams/NGDatagramPacket.m @@ -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)_address { + ASSIGN(self->sender, _address); +} +- (id)sender { + return self->sender; +} + +- (void)setReceiver:(id)_address { + ASSIGN(self->receiver, _address); +} +- (id)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 index 00000000..6d1b1c8e --- /dev/null +++ b/skyrix-core/NGStreams/NGDatagramSocket.m @@ -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 +# include +#endif + +#include +#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[2])_pair inDomain:(id)_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)_address { + volatile id sock = [[self alloc] initWithDomain:[_address domain]]; + + if (sock != nil) { + sock = AUTORELEASE(sock); + [sock bindToAddress:_address]; + } + return sock; +} + +- (id)initWithDomain:(id)_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)_factory { + ASSIGN(self->packetFactory, _factory); +} +- (id)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)_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)_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)_packet { + return [self sendPacket:_packet timeout:NGNoTimeout]; +} + +// receiving + +- (id)primaryReceivePacketWithMaxSize:(int)_maxSize { + id remote = nil; + id 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)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)receivePacketWithTimeout:(NSTimeInterval)_timeout { + return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:_timeout]; +} + +- (id)receivePacketWithMaxSize:(int)_maxPacketSize { + return [self receivePacketWithMaxSize:_maxPacketSize timeout:NGNoTimeout]; +} +- (id)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 index 00000000..cae34705 --- /dev/null +++ b/skyrix-core/NGStreams/NGDescriptorFunctions.m @@ -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 +# endif +# ifdef HAVE_SYS_POLL_H +# include +# endif +# ifndef POLLRDNORM +# define POLLRDNORM POLLIN /* needed on Linux */ +# endif +#else +# ifdef HAVE_SELECT_H +# include +# endif +#endif + +#if defined(HAVE_SYS_SOCKET_H) || defined(__APPLE__) +# include +#endif + +#ifdef HAVE_SYS_FCNTL_H +# include +#endif +#if defined(HAVE_FCNTL_H) || defined(__APPLE__) +# include +#endif + +#if HAVE_UNISTD_H || defined(__APPLE__) +# include +#endif +#if HAVE_LIMITS_H +# include +#endif +#if HAVE_SYS_TIME_H || defined(__APPLE__) +# include +#endif +#if HAVE_SYS_TYPES_H || defined(__APPLE__) +# include +#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 index 00000000..521ae74b --- /dev/null +++ b/skyrix-core/NGStreams/NGFileStream.m @@ -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 +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if HAVE_SYS_FCNTL_H +# include +#endif +#if HAVE_FCNTL_H || __APPLE__ +# include +#endif + +#include "common.h" +#import +#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 NGIn = nil; +NGStreams_DECLARE id NGOut = nil; +NGStreams_DECLARE id 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 index 00000000..06f52a60 --- /dev/null +++ b/skyrix-core/NGStreams/NGFilterStream.m @@ -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)_s { + return [[(NGFilterStream *)[self alloc] initWithInputSource:_s] autorelease]; +} ++ (id)filterWithOutputSource:(id)_s { + return [[(NGFilterStream *)[self alloc] initWithOutputSource:_s] autorelease]; +} ++ (id)filterWithSource:(id)_s { + return [[(NGFilterStream *)[self alloc] initWithSource:_s] autorelease]; +} + +- (id)init { + return [self initWithSource:nil]; +} + +- (id)initWithSource:(id)_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)_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)_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)inputStream { + return [self source]; +} +- (id)outputStream { + return [self source]; +} +- (id)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 index 00000000..ae1b76bb --- /dev/null +++ b/skyrix-core/NGStreams/NGFilterTextStream.m @@ -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)_s { + return [[(NGFilterTextStream *)[self alloc] initWithSource:_s] autorelease]; +} + +- (id)initWithSource:(id)_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)source { + return self->source; +} + +@end /* NGFilterTextStream */ diff --git a/skyrix-core/NGStreams/NGGZipStream.m b/skyrix-core/NGStreams/NGGZipStream.m new file mode 100644 index 00000000..396cda88 --- /dev/null +++ b/skyrix-core/NGStreams/NGGZipStream.m @@ -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 +#include +#include +#include "common.h" + +#ifdef Assert +#undef Assert +#endif + +#include +#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)_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 index 00000000..31e90131 --- /dev/null +++ b/skyrix-core/NGStreams/NGInternetSocketAddress.m @@ -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 +#endif +#if HAVE_NETINET_IN_H +# include +#endif +#if HAVE_UNISTD_H || defined(__APPLE__) +# include +#endif +#if defined(__APPLE__) +# include +#endif + +#if !defined(__CYGWIN32__) +# if HAVE_WINDOWS_H +# include +# endif +# if HAVE_WINSOCK_H +# include +# 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:@"", + 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 index 00000000..dd7d1c93 --- /dev/null +++ b/skyrix-core/NGStreams/NGInternetSocketDomain.m @@ -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 +#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)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)_address + forBindWithSocket:(id)_socket +{ + // nothing to prepare + return YES; +} +- (BOOL)cleanupAddress:(id)_address + afterCloseOfSocket:(id)_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:@"", (unsigned)self]; +} + +@end /* NGInternetSocketDomain */ diff --git a/skyrix-core/NGStreams/NGLocalSocketAddress.m b/skyrix-core/NGStreams/NGLocalSocketAddress.m new file mode 100644 index 00000000..3b92b3ac --- /dev/null +++ b/skyrix-core/NGStreams/NGLocalSocketAddress.m @@ -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 + +#if LIB_FOUNDATION_LIBRARY +# include +#endif + +#include "config.h" + +#if defined(__APPLE__) || defined(__FreeBSD__) +# include +#else +# include +#endif + +#if defined(HAVE_UNISTD_H) || defined(__APPLE__) +# include +#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 index 00000000..9d54b54e --- /dev/null +++ b/skyrix-core/NGStreams/NGLocalSocketDomain.m @@ -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 +# include +#else +# include +#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)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)_address + forBindWithSocket:(id)_socket +{ + if ([_socket conformsToProtocol:@protocol(NGPassiveSocket)]) { + NSString *path = [(NGLocalSocketAddress *)_address path]; + + // ignore errors .. + [[NSFileManager defaultManager] removeFileAtPath:path handler:nil]; + } + return YES; +} +- (BOOL)cleanupAddress:(id)_address + afterCloseOfSocket:(id)_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: + @"", (unsigned)self]; +} + +@end /* NGLocalSocketDomain */ + +#endif // !WIN32 diff --git a/skyrix-core/NGStreams/NGLockingStream.m b/skyrix-core/NGStreams/NGLockingStream.m new file mode 100644 index 00000000..d5f0cc4e --- /dev/null +++ b/skyrix-core/NGStreams/NGLockingStream.m @@ -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)_source lock:(id)_lock { + return [[[self alloc] initWithSource:_source lock:_lock] autorelease]; +} + +- (id)initWithSource:(id)_source lock:(id)_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)_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 index 00000000..330ef0f9 --- /dev/null +++ b/skyrix-core/NGStreams/NGNetUtilities.m @@ -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 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 index 00000000..bee820d6 --- /dev/null +++ b/skyrix-core/NGStreams/NGPassiveSocket.m @@ -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 +# include +#endif + +#if HAVE_SYS_ERRNO_H || defined(__APPLE__) +# include +#endif + +#include "common.h" + +@interface NGActiveSocket(privateMethods) + +- (id)_initWithDescriptor:(int)_fd + localAddress:(id)_local + remoteAddress:(id)_remote; + +@end + +@implementation NGPassiveSocket + ++ (id)socketBoundToAddress:(id)_address { + volatile id sock; + + sock = [[[self alloc] initWithDomain:[_address domain]] autorelease]; + [sock bindToAddress:_address]; + return sock; +} + +- (id)initWithDomain:(id)_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)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 @"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)accept { + // throws + // NGCouldNotAcceptException when the socket is not listening + // NGCouldNotAcceptException when the accept call failed + + id socket; + *(&socket) = nil; + + if (![self isListening]) { + [[[NGCouldNotAcceptException alloc] + initWithReason:@"socket is not listening" socket:self] raise]; + } + + SYNCHRONIZED(self->acceptLock) { + id local = nil; + id 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:@"", + [self localAddress]]; +} + +@end /* NGPassiveSocket */ diff --git a/skyrix-core/NGStreams/NGSocket+private.h b/skyrix-core/NGStreams/NGSocket+private.h new file mode 100644 index 00000000..13b394e5 --- /dev/null +++ b/skyrix-core/NGStreams/NGSocket+private.h @@ -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)_domain descriptor:(SOCKET)_fd; +#else +- (id)_initWithDomain:(id)_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 index 00000000..ec8931c4 --- /dev/null +++ b/skyrix-core/NGStreams/NGSocket.m @@ -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 +#include "NGSocketExceptions.h" +#include "NGSocket.h" +#include "NGSocket+private.h" +#include "NGInternetSocketDomain.h" + +#include "config.h" +#if defined(__APPLE__) +# include +# include +#endif + +#if defined(HAVE_UNISTD_H) || defined(__APPLE__) +# include +#endif + +#include "common.h" + +@interface _NGConcreteSocketFileHandle : NGConcreteStreamFileHandle +{ +} + +- (id)initWithSocket:(id)_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)_domain { + return [[[self alloc] initWithDomain:_domain] autorelease]; +} + +- (id)init { + return [self initWithDomain:[NGInternetSocketDomain domain]]; +} + +#if defined(WIN32) && !defined(__CYGWIN32__) +- (id)_initWithDomain:(id)_domain descriptor:(SOCKET)_fd { +#else +- (id)_initWithDomain:(id)_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)_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)_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)_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 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)localAddress { + return self->localAddress; +} + +- (BOOL)isBound { + return self->flags.isBound; +} + +- (int)socketType { + [self subclassResponsibility:_cmd]; + return -1; +} + +- (id)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)_socket { + return [super initWithStream:(id)_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 index 00000000..c01002e7 --- /dev/null +++ b/skyrix-core/NGStreams/NGSocketExceptions.m @@ -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 +#import +#import +#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)_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)socket { + return self->socket; +} + +@end /* NGSocketException */ + +@implementation NGCouldNotResolveHostNameException + +- (id)init { + return [self initWithHostName:@"" 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)_socket + domain:(id)_domain { + + if ((self = [super initWithReason:_reason socket:nil])) { + self->domain = [_domain retain]; + } + return self; +} + +- (void)dealloc { + [self->domain release]; + [super dealloc]; +} + +- (id)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)_domain { + if ((self = [super initWithReason:_reason socket:nil])) { + self->domain = [_domain retain]; + } + return self; +} + +- (void)dealloc { + [self->domain release]; + [super dealloc]; +} + +- (id)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)_socket + address:(id)_address { + + if ((self = [super initWithReason:_reason socket:_socket])) { + self->address = [_address retain]; + } + return self; +} + +- (void)dealloc { + [self->address release]; + [super dealloc]; +} + +- (id)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)_socket + address:(id)_address { + + if ((self = [super initWithReason:_reason socket:_socket])) { + self->address = [_address retain]; + } + return self; +} + +- (void)dealloc { + [self->address release]; + [super dealloc]; +} + +- (id)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)_socket { + return [self initWithStream:_socket reason:_reason]; +} + +- (id)initWithSocket:(id)_socket { + return [self initWithStream:_socket reason:@"the socket was shutdown"]; +} + +/* accessors */ + +- (id)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 index 00000000..61b0aa94 --- /dev/null +++ b/skyrix-core/NGStreams/NGStream+serialization.m @@ -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 +# endif +# if HAVE_SYS_SOCKET_H +# include +# endif +# if HAVE_NETINET_IN_H +# include +# endif +# include +#endif + +#include "common.h" +#include "NGStream+serialization.h" + +#if NeXT_RUNTIME +# include +#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)_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)_callback +{ + NGStreamDeserializeObjC(self, _value, _type, _callback); +} +#endif + +@end + +void NGStreamSerializeObjC(id self, + const void *_value, const char *_type, +#if USE_SERIALIZER + id _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 '=' + + 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 self, + void *_value, const char *_type, +#if USE_SERIALIZER + id _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 '=' + + 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 index 00000000..ca259eaf --- /dev/null +++ b/skyrix-core/NGStreams/NGStream.m @@ -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 _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 _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 _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 index 00000000..4c47dd6b --- /dev/null +++ b/skyrix-core/NGStreams/NGStreamCoder.m @@ -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 +#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)_stream { + return AUTORELEASE([[self alloc] initWithStream:_stream]); +} + +- (id)initWithStream:(id)_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)_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)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 "=" + + 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 "=" + + 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 "=" + + 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 index 00000000..91ab9b82 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreamExceptions.m @@ -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)_stream { + return [self initWithStream:_stream reason:[self defaultReason]]; +} + +- (id)initWithStream:(id)_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)_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)_stream { + return [[self alloc] initWithStream:_stream]; +} ++ (id)exceptionWithStream:(id)_stream reason:(NSString *)_reason { + return [[self alloc] initWithStream:_stream reason:_reason]; +} ++ (void)raiseWithStream:(id)_stream { + [[[self alloc] initWithStream:_stream] raise]; +} ++ (void)raiseWithStream:(id)_stream reason:(NSString *)_reason { + [[[self alloc] initWithStream:_stream reason:_reason] raise]; +} ++ (void)raiseWithStream:(id)_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)_stream { + return [self initWithStream:_stream + readCount:0 + safeCount:0 + data:nil]; +} + +- (id)initWithStream:(id)_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)_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)_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)_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 index 00000000..91c0ca51 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreamPipe.m @@ -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)streamForReading { + return self; +} +- (id)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 index 00000000..b6d085d4 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGStreams + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGStreams + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGStreams/NGStreams.m b/skyrix-core/NGStreams/NGStreams.m new file mode 100644 index 00000000..a26ac748 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams.m @@ -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 index 00000000..308a068c --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGActiveSSLSocket.h @@ -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 + +@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 index 00000000..47d06e66 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGActiveSocket+serialization.h @@ -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 +#if USE_SERIALIZER +# import +#endif +#include +#include + +@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)_callback; +- (void)deserializeDataAt:(void *)data ofObjCType:(const char*)type + context:(id)_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 index 00000000..b80808a5 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGActiveSocket.h @@ -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 +#include +#include +#include + +@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 remoteAddress; + NGStreamMode mode; + + NSTimeInterval receiveTimeout; + NSTimeInterval sendTimeout; +} + ++ (id)socketConnectedToAddress:(id)_address; +- (id)initWithDomain:(id)_domain; // designated initializer + +#if !defined(WIN32) ++ (BOOL)socketPair:(id[2])_pair inDomain:(id)_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)_address; + +- (BOOL)shutdown; // do a complete shutdown +- (BOOL)shutdownSendChannel; +- (BOOL)shutdownReceiveChannel; + +// ******************** accessors ********************* + +- (id)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 index 00000000..c3441ad0 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGBase64Stream.h @@ -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 + +/* + 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 index 00000000..0e7a5112 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGBufferedStream.h @@ -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 + +@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)_source bufferSize:(unsigned)_size; +- (id)initWithSource:(id)_source bufferSize:(unsigned)_size; +- (id)initWithSource:(id)_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 index 00000000..5d3295ff --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGByteBuffer.h @@ -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 +#include + +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)_stream la:(unsigned)_la; +- (id)initWithSource:(id)_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 index 00000000..3a2b00b6 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGByteCountStream.h @@ -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 + +@interface NGByteCountStream : NGFilterStream +{ +@protected + unsigned totalReadCount; + unsigned totalWriteCount; + unsigned char byteToCount; + unsigned byteReadCount; + unsigned byteWriteCount; +} + ++ (id)byteCounterForStream:(id)_stream byte:(unsigned char)_byte; +- (id)initWithSource:(id)_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 index 00000000..f611ddce --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGCTextStream.h @@ -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 +#include +#include +#include +#include + +@class NSEnumerator; + +NGStreams_EXPORT id NGTextIn; +NGStreams_EXPORT id NGTextOut; +NGStreams_EXPORT id 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 source; // retained + NGIOReadMethodType readBytes; + NGIOWriteMethodType writeBytes; + BOOL (*flushBuffer)(id, SEL); +} + ++ (id)textStreamWithInputSource:(id)_source; ++ (id)textStreamWithOutputSource:(id)_source; ++ (id)textStreamWithSource:(id)_stream; +- (id)initWithSource:(id)_stream; +- (id)initWithInputSource:(id)_source; +- (id)initWithOutputSource:(id)_source; + +// accessors + +- (id)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 index 00000000..1737f250 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGCharBuffer.h @@ -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 +#include +#include + +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)_source la:(int)_la; +- (id)initWithSource:(id)_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 index 00000000..738e9884 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGConcreteStreamFileHandle.h @@ -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 +#include + +@class NSData; + +@interface NGConcreteStreamFileHandle : NSFileHandle +{ + id stream; +} + +- (id)initWithStream:(id)_stream; + +// accessors + +- (id)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 index 00000000..cf4bfc36 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGDataStream.h @@ -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 +#include + +@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 index 00000000..830aac61 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGDatagramPacket.h @@ -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 +#include + +@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 sender; + id 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)_address; +- (id)sender; +- (void)setReceiver:(id)_address; +- (id)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 index 00000000..d8ef2d0c --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGDatagramSocket.h @@ -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 +#include +#include + +/* + 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 packetFactory; + int maxPacketSize; // default = 2048 + struct { + BOOL isConnected:1; + } udpFlags; +} + ++ (id)socketBoundToAddress:(id)_address; + +#if !defined(WIN32) ++ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain; +#endif + +// accessors + +- (void)setMaxPacketSize:(int)_maxPacketSize; +- (int)maxPacketSize; + +- (void)setPacketFactory:(id)_factory; +- (id)packetFactory; + +- (int)socketType; // returns SOCK_DGRAM + +// polling + +- (BOOL)wouldBlockInMode:(NGStreamMode)_mode; + +// sending + +// returns NO on timeout +- (BOOL)sendPacket:(id)_packet timeout:(NSTimeInterval)_timeout; +// blocks until data can be send +- (BOOL)sendPacket:(id)_packet; + +// receiving + +- (id)receivePacketWithMaxSize:(int)_maxPacketSize + timeout:(NSTimeInterval)_timeout; +- (id)receivePacketWithTimeout:(NSTimeInterval)_timeout; + +- (id)receivePacketWithMaxSize:(int)_maxPacketSize; +- (id)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 index 00000000..b120b3c3 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGDescriptorFunctions.h @@ -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 + +#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 index 00000000..353c35ee --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGFileStream.h @@ -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 +#endif +#ifdef HAVE_POLL_H +# include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#if defined(__MINGW32__) +# include +#endif + +#include +#include +#include + +@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 NGIn; +NGStreams_EXPORT id NGOut; +NGStreams_EXPORT id 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 index 00000000..ef92ced1 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGFilterStream.h @@ -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 + +@interface NGFilterStream : NGStream +{ +@protected + id source; + NGIOReadMethodType readBytes; + NGIOWriteMethodType writeBytes; +} + ++ (id)filterWithInputSource:(id)_source; ++ (id)filterWithOutputSource:(id)_source; ++ (id)filterWithSource:(id)_source; +- (id)initWithInputSource:(id)_source; +- (id)initWithOutputSource:(id)_source; +- (id)initWithSource:(id)_source; + +/* accessors */ + +- (id)inputStream; +- (id)outputStream; +- (id)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 index 00000000..a1205cd0 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGFilterTextStream.h @@ -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 + +@interface NGFilterTextStream : NGTextStream +{ + id source; +} + ++ (id)textFilterWithSource:(id)_source; +- (id)initWithSource:(id)_source; + +// accessors + +- (id)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 index 00000000..4a4dad18 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGGZipStream.h @@ -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 + +@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 index 00000000..730476f9 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGInternetSocketAddress.h @@ -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 +#include + +/* + 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 index 00000000..7cc60a89 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGInternetSocketDomain.h @@ -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 +#include + +/* + 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)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 index 00000000..4ed55287 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGLocalSocketAddress.h @@ -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 + +/* + 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 index 00000000..7d5d7770 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGLocalSocketDomain.h @@ -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 +#include + +/* + 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)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 index 00000000..0363c614 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGLockingStream.h @@ -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 +#include + +@interface NGLockingStream : NGFilterStream +{ +@private + id readLock; + id writeLock; + + void (*_lockMethod)(id, SEL); + void (*_unlockMethod)(id, SEL); +} + ++ (id)filterWithSource:(id)_source lock:(id)_lock; +- (id)initWithSource:(id)_source lock:(id)_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 index 00000000..7910c441 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGNet.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(WIN32) +# include +# include +#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 index 00000000..08779c4a --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGNetDecls.h @@ -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 index 00000000..d282f83f --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGNetUtilities.h @@ -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 +#include + +/* + 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 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 index 00000000..36b37538 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGPassiveSocket.h @@ -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 +#include +#include + +/* + 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 acceptLock; // prevents file-locking + int backlogSize; +} + ++ (id)socketBoundToAddress:(id)_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)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 index 00000000..6024e508 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGSocket.h @@ -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 +#include + +#if defined(WIN32) +# include +#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 domain; + id 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)_domain; +- (id)initWithDomain:(id)_domain; // designated initializer + +// ************************* create a socket ***************** + +- (BOOL)primaryCreateSocket; +- (BOOL)close; + +// ************************* bind a socket ******************* + +// throws +// NGSocketAlreadyBoundException if the socket is already bound +- (BOOL)bindToAddress:(id)_address; + +// throws +// NGSocketAlreadyBoundException if the socket is already bound +- (BOOL)kernelBoundAddress; + +// ************************* accessors *********************** + +- (id)localAddress; +- (BOOL)isBound; + +- (void)setLastException:(NSException *)_exception; +- (NSException *)lastException; +- (void)resetLastException; + +- (int)socketType; // abstract +- (id)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 index 00000000..d045e30f --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGSocketExceptions.h @@ -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 +#include +#include + +/* + 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 socket; +} + +- (id)init; +- (id)initWithReason:(NSString *)_reason; +- (id)initWithReason:(NSString *)_reason socket:(id)_socket; + +- (id)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 domain; +} + +- (id)initWithReason:(NSString *)_reason + socket:(id)_socket domain:(id)_domain; + +@end + +@interface NGCouldNotCreateSocketException : NGSocketException +{ +@protected + id domain; +} + +- (id)init; +- (id)initWithReason:(NSString *)_reason domain:(id)_domain; + +@end + +// ******************** bind *********************** + +@interface NGSocketBindException : NGSocketException +@end + +@interface NGSocketAlreadyBoundException : NGSocketBindException +@end + +@interface NGCouldNotBindSocketException : NGSocketBindException +{ +@protected + id address; +} + +- (id)initWithReason:(NSString *)_reason + socket:(id)_socket address:(id)address; + +- (id)address; + +@end + +// ******************** connect ******************** + +@interface NGSocketConnectException : NGSocketException +@end + +@interface NGSocketNotConnectedException : NGSocketConnectException +@end + +@interface NGSocketAlreadyConnectedException : NGSocketConnectException +@end + +@interface NGCouldNotConnectException : NGSocketConnectException +{ +@protected + id address; +} + +- (id)initWithReason:(NSString *)_reason + socket:(id)_socket + address:(id)address; + +- (id)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)_socket; +- (id)initWithSocket:(id)_socket; + +/* Note: this only returns a valid ptr, if the socket is still retained ! */ +- (id)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 index 00000000..e3f9796a --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGSocketProtocols.h @@ -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 +#include + +@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)localAddress; +- (BOOL)bindToAddress:(id)_localAddress; +- (BOOL)close; + +- (NSException *)lastException; + +@end + +// domains + +@protocol NGSocketDomain < NSObject > + +- (id)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)_address + forBindWithSocket:(id)_socket; +- (BOOL)cleanupAddress:(id)_address + afterCloseOfSocket:(id)_socket; + +@end + +// concrete sockets + +@protocol NGActiveSocket < NGSocket, NGStream, NGByteSequenceStream > + +- (BOOL)connectToAddress:(id)_address; +- (BOOL)shutdown; + +- (BOOL)isConnected; + +- (id)remoteAddress; + +@end + +@protocol NGPassiveSocket < NGSocket > + +- (BOOL)listenWithBacklog:(int)_backlogSize; +- (id)accept; + +@end + +// packets + +@protocol NGDatagramPacket < NSObject > + +- (void)setSender:(id)_address; +- (id)sender; +- (void)setReceiver:(id)_address; +- (id)receiver; + +- (NSData *)data; + +@end + +@protocol NGDatagramPacketFactory < NSObject > + +- (id)packetWithData:(NSData *)_data; + +- (id) + 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 index 00000000..1bfb94ee --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStream+serialization.h @@ -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 +#include +#include + +#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED) +# define USE_SERIALIZER 1 +# import +#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)_callback; +- (void)deserializeDataAt:(void *)data ofObjCType:(const char*)type + context:(id)_callback; +#endif + +@end + +NGStreams_EXPORT void +NGStreamSerializeObjC(id self, + const void *_data, const char *_type, +#if USE_SERIALIZER + id _callback +#else + id _callback +#endif + ); + +NGStreams_EXPORT void +NGStreamDeserializeObjC(id self, + void *_data, const char *_type, +#if USE_SERIALIZER + id _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 index 00000000..b4afec55 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStream.h @@ -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 +#include +#include + +@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 _stream); + +NGStreams_EXPORT BOOL +NGSafeReadBytesFromStream(id _in, void *_buf, unsigned _len); + +NGStreams_EXPORT BOOL +NGSafeWriteBytesToStream(id _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 index 00000000..875ad3f8 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreamCoder.h @@ -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 + +#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED) +# define USE_SERIALIZER 1 +# import +#endif + +#import +#import +#include + +@interface NGStreamCoder : NSCoder +#if USE_SERIALIZER + < NSObjCTypeSerializationCallBack > +#endif +{ +@protected + id 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)_stream; +- (id)initWithStream:(id)_stream; + +// accessors + +- (id)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 index 00000000..6719b4fd --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreamExceptions.h @@ -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 +#include + +@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)_stream; +- (id)initWithStream:(id)_stream reason:(NSString *)_reason; +- (id)initWithStream:(id)_stream format:(NSString *)_format,...; ++ (id)exceptionWithStream:(id)_stream; ++ (id)exceptionWithStream:(id)_stream reason:(NSString *)_reason; ++ (void)raiseWithStream:(id)_stream; ++ (void)raiseWithStream:(id)_stream format:(NSString *)_format,...; ++ (void)raiseWithStream:(id)_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)_stream; + +- (id)initWithStream:(id)_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)_stream errorCode:(int)_code; ++ (void)raiseWithStream:(id)_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)_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 index 00000000..bced5bfb --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreamPipe.h @@ -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 + +@interface NGStreamPipe : NSPipe < NGStream, NGByteSequenceStream > +{ +@private + int fildes[2]; + NSFileHandle *fhIn; + NSFileHandle *fhOut; +} + ++ (id)pipe; +- (id)init; + +- (NSFileHandle *)fileHandleForReading; +- (NSFileHandle *)fileHandleForWriting; + +- (id)streamForReading; +- (id)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 index 00000000..4cbd8ffc --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreamProtocols.h @@ -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 + +#if !(MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED) +# define USE_SERIALIZER 1 +# import +#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 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)_callback; +- (void)deserializeDataAt:(const void*)data ofObjCType:(const char*)type + context:(id)_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 index 00000000..21e40239 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreams.h @@ -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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// 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 index 00000000..52f040ab --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStreamsDecls.h @@ -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 index 00000000..556890f9 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGStringTextStream.h @@ -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 +#include + +@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 index 00000000..fcb07d70 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGTaskStream.h @@ -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 + +@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 index 00000000..19f445f5 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGTerminalSupport.h @@ -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 +#include + +@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 index 00000000..7a5b4f21 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGTextStream.h @@ -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 +#include + +@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 index 00000000..10f962f5 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGTextStreamProtocols.h @@ -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 +#import + +@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 index 00000000..38903f04 --- /dev/null +++ b/skyrix-core/NGStreams/NGStreams/NGUrlChars.h @@ -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 index 00000000..7df2cdff --- /dev/null +++ b/skyrix-core/NGStreams/NGStringTextStream.m @@ -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 index 00000000..a62d3fd3 --- /dev/null +++ b/skyrix-core/NGStreams/NGTaskStream.m @@ -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 index 00000000..184ca671 --- /dev/null +++ b/skyrix-core/NGStreams/NGTerminalSupport.m @@ -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 index 00000000..037aa67e --- /dev/null +++ b/skyrix-core/NGStreams/NGTextStream.m @@ -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 index 00000000..fc00e33d --- /dev/null +++ b/skyrix-core/NGStreams/README @@ -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) + 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 index 00000000..f0daa7c5 --- /dev/null +++ b/skyrix-core/NGStreams/SxCore-NGStreams.graffle @@ -0,0 +1,4989 @@ + + + + + CanvasColor + + w + 1.000000e+00 + + ColumnAlign + 0 + ColumnSpacing + 5.400000e+01 + GraphDocumentVersion + 2 + GraphicsList + + + Class + Group + Graphics + + + Bounds + {{639, 1332}, {225, 18}} + Class + ShapedGraphic + ID + 8385 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{720, 1359}, {225, 18}} + Class + ShapedGraphic + ID + 8386 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{702, 1296}, {171, 18}} + Class + ShapedGraphic + ID + 8387 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8385 + + ID + 8388 + Points + + {778.5, 1314} + {760.5, 1332} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8387 + + + + Class + LineGraphic + Head + + ID + 8386 + + ID + 8389 + Points + + {793.929, 1314} + {826.071, 1359} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8387 + + + + ID + 8384 + + + Bounds + {{567, 999}, {234, 18}} + Class + ShapedGraphic + ID + 8383 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{324, 315}, {126, 18}} + Class + ShapedGraphic + ID + 8368 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGBase64Stream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{396, 279}, {126, 18}} + Class + ShapedGraphic + ID + 8369 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLockingStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{252, 279}, {126, 18}} + Class + ShapedGraphic + ID + 8370 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGMD5Stream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{396, 252}, {126, 18}} + Class + ShapedGraphic + ID + 8371 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteBuffer.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{396, 225}, {126, 18}} + Class + ShapedGraphic + ID + 8372 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGByteCountStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{252, 252}, {126, 18}} + Class + ShapedGraphic + ID + 8373 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGBufferedStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{252, 225}, {126, 18}} + Class + ShapedGraphic + ID + 8374 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGGZipStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{324, 189}, {126, 18}} + Class + ShapedGraphic + ID + 8375 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFilterStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8368 + + ID + 8376 + Points + + {387, 207} + {387, 315} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8369 + + ID + 8377 + Points + + {394.2, 207} + {451.8, 279} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8370 + + ID + 8378 + Points + + {379.8, 207} + {322.2, 279} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8371 + + ID + 8379 + Points + + {397.286, 207} + {448.714, 252} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8372 + + ID + 8380 + Points + + {405, 207} + {441, 225} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8373 + + ID + 8381 + Points + + {376.714, 207} + {325.286, 252} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + Class + LineGraphic + Head + + ID + 8374 + + ID + 8382 + Points + + {369, 207} + {333, 225} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8375 + + + + ID + 8367 + + + Bounds + {{36, 981}, {207, 18}} + Class + ShapedGraphic + ID + 8366 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{117, 1404}, {243, 18}} + Class + ShapedGraphic + ID + 8357 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{18, 1377}, {243, 18}} + Class + ShapedGraphic + ID + 8358 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{117, 1350}, {243, 18}} + Class + ShapedGraphic + ID + 8359 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{54, 1287}, {279, 18}} + Class + ShapedGraphic + ID + 8360 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{18, 1323}, {243, 18}} + Class + ShapedGraphic + ID + 8361 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8357 + + ID + 8362 + Points + + {196.962, 1305} + {235.038, 1404} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8360 + + + + Class + LineGraphic + Head + + ID + 8358 + + ID + 8363 + Points + + {188.1, 1305} + {144.9, 1377} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8360 + + + + Class + LineGraphic + Head + + ID + 8359 + + ID + 8364 + Points + + {199.929, 1305} + {232.071, 1350} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8360 + + + + Class + LineGraphic + Head + + ID + 8361 + + ID + 8365 + Points + + {180, 1305} + {153, 1323} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8360 + + + + ID + 8356 + + + Bounds + {{567, 972}, {234, 18}} + Class + ShapedGraphic + ID + 8355 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{225, 1089}, {180, 18}} + Class + ShapedGraphic + ID + 8348 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{333, 1062}, {180, 18}} + Class + ShapedGraphic + ID + 8349 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{225, 1035}, {180, 18}} + Class + ShapedGraphic + ID + 8350 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{279, 999}, {153, 18}} + Class + ShapedGraphic + ID + 8351 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8348 + + ID + 8352 + Points + + {351.45, 1017} + {319.05, 1089} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8351 + + + + Class + LineGraphic + Head + + ID + 8349 + + ID + 8353 + Points + + {365.143, 1017} + {413.357, 1062} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8351 + + + + Class + LineGraphic + Head + + ID + 8350 + + ID + 8354 + Points + + {345.375, 1017} + {325.125, 1035} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8351 + + + + ID + 8347 + + + Class + Group + Graphics + + + Bounds + {{171, 540}, {126, 18}} + Class + ShapedGraphic + ID + 8334 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDatagramSocket.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{315, 567}, {117, 18}} + Class + ShapedGraphic + ID + 8335 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{171, 567}, {126, 18}} + Class + ShapedGraphic + ID + 8336 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGActiveSocket.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{315, 513}, {117, 18}} + Class + ShapedGraphic + ID + 8337 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{171, 513}, {126, 18}} + Class + ShapedGraphic + ID + 8338 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGPassiveSocket.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 576}, {81, 18}} + Class + ShapedGraphic + ID + 8339 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{45, 540}, {81, 18}} + Class + ShapedGraphic + ID + 8340 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocket.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8334 + + ID + 8341 + Points + + {126, 549} + {171, 549} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8340 + + + + Class + LineGraphic + Head + + ID + 8336 + + ID + 8342 + Points + + {315, 576} + {297, 576} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8335 + + + + Class + LineGraphic + Head + + ID + 8336 + + ID + 8343 + Points + + {124.876, 556.159} + {184.5, 567} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8340 + + + + Class + LineGraphic + Head + + ID + 8338 + + ID + 8344 + Points + + {315, 522} + {297, 522} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8337 + + + + Class + LineGraphic + Head + + ID + 8338 + + ID + 8345 + Points + + {124.876, 541.841} + {184.5, 531} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8340 + + + + Class + LineGraphic + Head + + ID + 8340 + + ID + 8346 + Points + + {85.5, 576} + {85.5, 558} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8339 + + + + ID + 8333 + + + Class + Group + Graphics + + + Bounds + {{558, 1179}, {198, 18}} + Class + ShapedGraphic + ID + 8329 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{585, 1143}, {171, 18}} + Class + ShapedGraphic + ID + 8330 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{603, 1206}, {198, 18}} + Class + ShapedGraphic + ID + 8331 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8331 + + ID + 8332 + Points + + {675, 1161} + {697.5, 1206} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8330 + + + + ID + 8328 + + + Bounds + {{567, 945}, {234, 18}} + Class + ShapedGraphic + ID + 8327 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{99, 684}, {126, 18}} + Class + ShapedGraphic + ID + 8316 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCharBuffer.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{243, 684}, {126, 18}} + Class + ShapedGraphic + ID + 8317 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStringTextStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{99, 648}, {126, 18}} + Class + ShapedGraphic + ID + 8318 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFilterTextStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{306, 648}, {126, 18}} + Class + ShapedGraphic + ID + 8319 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGCTextStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{297, 612}, {153, 18}} + Class + ShapedGraphic + ID + 8320 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTextStreamProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{153, 612}, {126, 18}} + Class + ShapedGraphic + ID + 8321 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTextStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8316 + + ID + 8322 + Points + + {162, 666} + {162, 684} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8318 + + + + Class + LineGraphic + Head + + ID + 8317 + + ID + 8323 + Points + + {227.25, 630} + {294.75, 684} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8321 + + + + Class + LineGraphic + Head + + ID + 8318 + + ID + 8324 + Points + + {202.5, 630} + {175.5, 648} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8321 + + + + Class + LineGraphic + Head + + ID + 8319 + + ID + 8325 + Points + + {254.25, 630} + {330.75, 648} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8321 + + + + Class + LineGraphic + Head + + ID + 8321 + + ID + 8326 + Points + + {297, 621} + {279, 621} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8320 + + + + ID + 8315 + + + Class + Group + Graphics + + + Bounds + {{234, 1233}, {180, 18}} + Class + ShapedGraphic + ID + 8308 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{234, 1179}, {180, 18}} + Class + ShapedGraphic + ID + 8309 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{270, 1134}, {207, 18}} + Class + ShapedGraphic + ID + 8310 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{306, 1206}, {207, 18}} + Class + ShapedGraphic + ID + 8311 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8308 + + ID + 8312 + Points + + {369, 1152} + {328.5, 1233} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8310 + + + + Class + LineGraphic + Head + + ID + 8309 + + ID + 8313 + Points + + {363.6, 1152} + {333.9, 1179} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8310 + + + + Class + LineGraphic + Head + + ID + 8311 + + ID + 8314 + Points + + {378, 1152} + {405, 1206} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8310 + + + + ID + 8307 + + + Bounds + {{567, 918}, {234, 18}} + Class + ShapedGraphic + ID + 8306 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{351, 837}, {171, 18}} + Class + ShapedGraphic + ID + 8305 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{99, 234}, {90, 18}} + Class + ShapedGraphic + ID + 8302 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{54, 270}, {180, 18}} + Class + ShapedGraphic + ID + 8303 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGConcreteStreamFileHandle.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8303 + + ID + 8304 + Points + + {144, 252} + {144, 270} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8302 + + + + ID + 8301 + + + Bounds + {{567, 891}, {234, 18}} + Class + ShapedGraphic + ID + 8300 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{189, 837}, {144, 18}} + Class + ShapedGraphic + ID + 8299 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{837, 1116}, {225, 18}} + Class + ShapedGraphic + ID + 8292 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{801, 1143}, {198, 18}} + Class + ShapedGraphic + ID + 8293 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{837, 1053}, {171, 18}} + Class + ShapedGraphic + ID + 8294 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{801, 1089}, {198, 18}} + Class + ShapedGraphic + ID + 8295 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8292 + + ID + 8296 + Points + + {926.357, 1071} + {945.643, 1116} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8294 + + + + Class + LineGraphic + Head + + ID + 8293 + + ID + 8297 + Points + + {920.25, 1071} + {902.25, 1143} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8294 + + + + Class + LineGraphic + Head + + ID + 8295 + + ID + 8298 + Points + + {916.875, 1071} + {905.625, 1089} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8294 + + + + ID + 8291 + + + Class + Group + Graphics + + + Bounds + {{45, 306}, {207, 18}} + Class + ShapedGraphic + ID + 8289 + Shape + Rectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{45, 342}, {207, 18}} + Class + ShapedGraphic + ID + 8290 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamCoder.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 8288 + + + Class + Group + Graphics + + + Bounds + {{45, 477}, {153, 18}} + Class + ShapedGraphic + ID + 8283 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGInternetSocketDomain.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{216, 468}, {117, 18}} + Class + ShapedGraphic + ID + 8284 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{45, 450}, {153, 18}} + Class + ShapedGraphic + ID + 8285 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLocalSocketDomain.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8283 + + ID + 8286 + Points + + {216, 480.441} + {197.975, 481.501} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8284 + + + + Class + LineGraphic + Head + + ID + 8285 + + ID + 8287 + Points + + {216, 470.118} + {194.883, 467.633} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8284 + + + + ID + 8282 + + + Class + Group + Graphics + + + Bounds + {{252, 72}, {99, 18}} + Class + ShapedGraphic + ID + 8277 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDataStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{369, 45}, {135, 18}} + Class + ShapedGraphic + ID + 8278 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{252, 27}, {99, 18}} + Class + ShapedGraphic + ID + 8279 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGFileStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8277 + + ID + 8280 + Points + + {391.5, 63} + {346.415, 72.017} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8278 + + + + Class + LineGraphic + Head + + ID + 8279 + + ID + 8281 + Points + + {369, 45} + {350.325, 42.51} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8278 + + + + ID + 8276 + + + Class + Group + Graphics + + + Bounds + {{72, 27}, {99, 18}} + Class + ShapedGraphic + ID + 8273 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{72, 63}, {99, 18}} + Class + ShapedGraphic + ID + 8274 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamPipe.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8274 + + ID + 8275 + Points + + {121.5, 45} + {121.5, 63} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8273 + + + + ID + 8272 + + + Bounds + {{306, 936}, {207, 18}} + Class + ShapedGraphic + ID + 8271 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{27, 1197}, {162, 18}} + Class + ShapedGraphic + ID + 8270 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{207, 774}, {108, 18}} + Class + ShapedGraphic + ID + 8269 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{567, 864}, {234, 18}} + Class + ShapedGraphic + ID + 8268 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{198, 900}, {126, 18}} + Class + ShapedGraphic + ID + 8267 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{18, 945}, {207, 18}} + Class + ShapedGraphic + ID + 8266 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{729, 774}, {126, 18}} + Class + ShapedGraphic + ID + 8265 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{567, 837}, {234, 18}} + Class + ShapedGraphic + ID + 8264 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketExceptions.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{351, 459}, {153, 18}} + Class + ShapedGraphic + ID + 8261 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGInternetSocketAddress.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{216, 441}, {117, 18}} + Class + ShapedGraphic + ID + 8262 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{351, 432}, {153, 18}} + Class + ShapedGraphic + ID + 8263 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGLocalSocketAddress.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 8260 + + + Class + LineGraphic + Head + + ID + 8261 + + ID + 8259 + Points + + {333, 456.882} + {354.117, 459.367} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8262 + + + + Class + LineGraphic + Head + + ID + 8263 + + ID + 8258 + Points + + {333, 446.559} + {351.025, 445.499} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8262 + + + + Bounds + {{342, 108}, {99, 18}} + Class + ShapedGraphic + ID + 8257 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGTaskStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + Group + Graphics + + + Bounds + {{216, 387}, {126, 18}} + Class + ShapedGraphic + ID + 8255 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGSocketProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{45, 387}, {153, 18}} + Class + ShapedGraphic + ID + 8256 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGDatagramPacket.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + ID + 8254 + + + Class + LineGraphic + Head + + ID + 8256 + + ID + 8253 + Points + + {216, 396} + {198, 396} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8255 + + + + Bounds + {{207, 738}, {108, 18}} + Class + ShapedGraphic + ID + 8252 + Shape + RoundedRectangle + Style + + fill + + Color + + b + 5.000000e-01 + g + 1.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Bounds + {{45, 189}, {81, 18}} + Class + ShapedGraphic + ID + 8251 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{117, 117}, {153, 18}} + Class + ShapedGraphic + ID + 8250 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStreamProtocols.h + + Shape + Rectangle + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + + + Text + + Text + {\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} + + + + Bounds + {{153, 189}, {81, 18}} + Class + ShapedGraphic + ID + 8249 + Link + + url + file://localhost/Volumes/Jaguar/Users/helge/dev/pkg42/skyrix-core-42/NGStreams/NGStreams/NGStream.h + + Shape + RoundedRectangle + Text + + Text + {\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\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} + + + + Class + LineGraphic + Head + + ID + 8383 + + ID + 8248 + Points + + {787.68, 792} + {688.32, 999} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8366 + + ID + 8247 + Points + + {247.5, 918} + {153, 981} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8269 + + ID + 8246 + Points + + {261, 756} + {261, 774} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8252 + + + + Class + LineGraphic + Head + + ID + 8355 + + ID + 8245 + Points + + {787.091, 792} + {688.909, 972} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8329 + + ID + 8244 + Points + + {667.125, 1161} + {660.375, 1179} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8330 + + + + Class + LineGraphic + Head + + ID + 8294 + + ID + 8243 + Points + + {796.21, 792} + {918.29, 1053} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8360 + + ID + 8242 + Points + + {116.55, 1215} + {184.95, 1287} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8270 + + + + Class + LineGraphic + Head + + ID + 8327 + + ID + 8241 + Points + + {786.316, 792} + {689.684, 945} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8387 + + ID + 8240 + Points + + {791.922, 792} + {787.578, 1296} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8330 + + ID + 8239 + Points + + {789.037, 792} + {673.463, 1143} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8306 + + ID + 8238 + Points + + {785.25, 792} + {690.75, 918} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8305 + + ID + 8237 + Points + + {333, 846} + {351, 846} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8299 + + + + Class + LineGraphic + Head + + ID + 8300 + + ID + 8236 + Points + + {783.692, 792} + {692.308, 891} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8299 + + ID + 8235 + Points + + {261, 792} + {261, 837} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8269 + + + + Class + LineGraphic + Head + + ID + 8290 + + ID + 8234 + Points + + {148.5, 324} + {148.5, 342} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8289 + + + + Class + LineGraphic + Head + + ID + 8277 + + ID + 8233 + Points + + {201.808, 189} + {293.192, 90} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8249 + + + + Class + LineGraphic + Head + + ID + 8274 + + ID + 8232 + Points + + {88.0714, 189} + {118.929, 81} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8251 + + + + Class + LineGraphic + Head + + ID + 8274 + + ID + 8231 + Points + + {181.5, 117} + {133.5, 81} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8250 + + + + Class + LineGraphic + Head + + ID + 8279 + + ID + 8230 + Points + + {199.5, 189} + {295.5, 45} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8249 + + + + Class + LineGraphic + Head + + ID + 8271 + + ID + 8229 + Points + + {298.125, 918} + {372.375, 936} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8351 + + ID + 8228 + Points + + {269.591, 918} + {346.909, 999} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8310 + + ID + 8227 + Points + + {265.327, 918} + {369.173, 1134} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8267 + + ID + 8226 + Points + + {261, 792} + {261, 900} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8269 + + + + Class + LineGraphic + Head + + ID + 8375 + + ID + 8225 + Points + + {234, 198} + {324, 198} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8249 + + + + Class + LineGraphic + Head + + ID + 8270 + + ID + 8224 + Points + + {256.364, 918} + {112.636, 1197} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8265 + + ID + 8223 + Points + + {315, 783} + {729, 783} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8269 + + + + Class + LineGraphic + Head + + ID + 8268 + + ID + 8222 + Points + + {781.2, 792} + {694.8, 864} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8266 + + ID + 8221 + Points + + {233.1, 918} + {149.4, 945} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8267 + + + + Class + LineGraphic + Head + + ID + 8264 + + ID + 8220 + Points + + {776.571, 792} + {699.429, 837} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8265 + + + + Class + LineGraphic + Head + + ID + 8257 + + ID + 8219 + Points + + {215.5, 189} + {369.5, 126} + + Style + + stroke + + HeadArrow + FilledArrow + TailArrow + 0 + + + Tail + + ID + 8249 + + + + Class + LineGraphic + Head + + ID + 8249 + + ID + 8218 + Points + + {126, 198} + {153, 198} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8251 + + + + Class + LineGraphic + Head + + ID + 8249 + + ID + 8217 + Points + + {193.5, 135} + {193.5, 189} + + Style + + stroke + + Color + + b + 0.000000e+00 + g + 0.000000e+00 + r + 1.000000e+00 + + HeadArrow + 0 + TailArrow + FilledBall + + + Tail + + ID + 8250 + + + + Class + LineGraphic + Head + + ID + 8251 + + ID + 8216 + Points + + {85.5, 576} + {85.5, 207} + + Style + + stroke + + HeadArrow + FilledDiamond + LineType + 1 + TailArrow + 0 + + + Tail + + ID + 8339 + + + + GridInfo + + HPages + 4 + ImageCounter + 1 + IsPalette + NO + Layers + + + Lock + NO + Name + Layer 1 + Print + YES + View + YES + + + LayoutInfo + + AutoAdjust + YES + HierarchicalOrientation + 0 + MagneticFieldCenter + {0, 0} + + MagnetsEnabled + YES + PageBreakColor + + w + 3.333333e-01 + + PageBreaks + YES + PageSetup + + BAt0eXBlZHN0cmVhbYED6IQBQISEhAtOU1ByaW50SW5mbwGEhAhOU09iamVjdACFkoSE + hBNOU011dGFibGVEaWN0aW9uYXJ5AISEDE5TRGljdGlvbmFyeQCUhAFpEpKEhIQITlNT + dHJpbmcBlIQBKxBOU0pvYkRpc3Bvc2l0aW9uhpKEmZkPTlNQcmludFNwb29sSm9ihpKE + mZkOTlNCb3R0b21NYXJnaW6GkoSEhAhOU051bWJlcgCEhAdOU1ZhbHVlAJSEASqEhAFm + nSSGkoSZmQtOU1BhcGVyTmFtZYaShJmZBkxldHRlcoaShJmZD05TUHJpbnRBbGxQYWdl + c4aShJ2chIQBc54AhpKEmZkNTlNSaWdodE1hcmdpboaShJ2cn50khpKEmZkITlNDb3Bp + ZXOGkoSdnISEAVOfAYaShJmZD05TU2NhbGluZ0ZhY3RvcoaShJ2chIQBZKABhpKEmZkL + TlNGaXJzdFBhZ2WGkoSdnKmfAYaShJmZFE5TVmVydGljYWxQYWdpbmF0aW9uhpKEnZyk + ngCGkoSZmRVOU0hvcml6b25hbFBhZ2luYXRpb26GkoSdnKSeAIaShJmZFk5TSG9yaXpv + bnRhbGx5Q2VudGVyZWSGkoSdnKSeAYaShJmZDE5TTGVmdE1hcmdpboaShJ2cn50khpKE + mZkNTlNPcmllbnRhdGlvboaShJ2cpJ4AhpKEmZkZTlNQcmludFJldmVyc2VPcmllbnRh + dGlvboaSo5KEmZkKTlNMYXN0UGFnZYaShJ2chJeXgn////+GkoSZmQtOU1RvcE1hcmdp + boaShJ2cn50khpKEmZkUTlNWZXJ0aWNhbGx5Q2VudGVyZWSGkrSShJmZC05TUGFwZXJT + aXplhpKEnpyEhAx7X05TU2l6ZT1mZn2hgQJkgQMYhoaG + + RowAlign + 0 + RowSpacing + 9.000000e+00 + VPages + 2 + WindowInfo + + Frame + {{185, 90}, {794, 751}} + VisibleRegion + {{0, 0}, {1038.67, 898.667}} + Zoom + 0.75 + + + diff --git a/skyrix-core/NGStreams/TODO b/skyrix-core/NGStreams/TODO new file mode 100644 index 00000000..a81847fb --- /dev/null +++ b/skyrix-core/NGStreams/TODO @@ -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 index 00000000..b64cd580 --- /dev/null +++ b/skyrix-core/NGStreams/Version @@ -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 index 00000000..b7fd8490 --- /dev/null +++ b/skyrix-core/NGStreams/common.h @@ -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 + +// configuration + +#include "config.h" + +#if defined(WIN32) +# include +# include +#endif + +#if LIB_FOUNDATION_BOEHM_GC +# include +#endif + +#ifdef GNU_RUNTIME +# include +# include +# include +#endif + +#if WITH_FOUNDATION_EXT +#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY +# import +# import +# import +# import +# import +# import +# import +#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 + +/* system config */ + +#if !defined(__CYGWIN32__) +# ifdef HAVE_WINDOWS_H +# include +# endif +# ifdef HAVE_WINSOCK_H +# include +# endif +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#if HAVE_SYS_TYPES_H +# include +#endif + +#ifndef __MINGW32__ +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif + +#if !defined(WIN32) || defined(__CYGWIN32__) +# include +# include +#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 index 00000000..378eab84 --- /dev/null +++ b/skyrix-core/NGStreams/config.guess @@ -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 . +# Please send patches to . +# +# 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 ." + +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 <$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 /* 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 + + 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 + #include + + 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 + 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 < /* 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 < +#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 <$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 < +#ifdef __cplusplus +#include /* 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' /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 + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 < +# include +#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 + 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 +# 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 < 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 index 00000000..7e88a578 --- /dev/null +++ b/skyrix-core/NGStreams/config.h.in @@ -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 header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file */ +#undef HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LIBC_H + +/* Define if you have the header file */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file */ +#undef HAVE_SYS_FCNTL_H + +/* Define if you have the header file */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file */ +#undef HAVE_SYS_VFS_H + +/* Define if you have the header file */ +#undef HAVE_SYS_STATFS_H + +/* Define if you have the header file */ +#undef HAVE_SYS_STATVFS_H + +/* Define if you have the header file */ +#undef HAVE_POLL_H + +/* Define if you have the header file */ +#undef HAVE_SYS_POLL_H + +/* Define if you have the header file */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the header file */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the header file */ +#undef HAVE_SYS_FILIO_H + +/* Define if you have the header file */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the header file */ +#undef HAVE_NETDB_H + +/* Define if you have the header file */ +#undef HAVE_WINDOWS_H + +/* Define if you have the header file */ +#undef HAVE_WINSOCK_H + +/* Define if you have the header file */ +#undef HAVE_WINDOWS32_SOCKETS_H + +/* Define if you have the header file */ +#undef HAVE_PWD_H + +/* Define if you have the header file */ +#undef HAVE_PROCESS_H + +/* Define if you have the header file */ +#undef HAVE_GRP_H + +/* Define if you have the header file */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file */ +#undef HAVE_TIME_H + +/* Define if you have the header file */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the header file */ +#undef HAVE_UTIME_H + +/* Define if you have the 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 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 +#endif +#if HAVE_SYS_POLL_H +# include +#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 index 00000000..4ac0c8b0 --- /dev/null +++ b/skyrix-core/NGStreams/config.sub @@ -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 . +# +# 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 ." + +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 index 00000000..454727cf --- /dev/null +++ b/skyrix-core/NGStreams/configure @@ -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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 < +#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 <&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 <&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 <&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 < +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 < +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 < +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 +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 <&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 < +#include +#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 < +/* 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 <&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 +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 <&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 < +/* 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 <&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 < +#include +#include + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include +# 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 +# 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 < +#include +#include +#include +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 +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 +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 < +#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 < +#if STDC_HEADERS +#include +#include +#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 +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 < +/* 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 < +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#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 , + but some compilers (e.g. gcc -O) don't grok . + 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 < +#include +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 </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 < 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 <> $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 <> $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 <> $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 <> $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 index 00000000..98dddf4e --- /dev/null +++ b/skyrix-core/NGStreams/configure.in @@ -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 index 00000000..58719246 --- /dev/null +++ b/skyrix-core/NGStreams/install-sh @@ -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 index 00000000..36f9d5ae --- /dev/null +++ b/skyrix-core/NGStreams/libNGStreams.def @@ -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 index 00000000..4ad6ec49 --- /dev/null +++ b/skyrix-core/NGStreams/macosx/config.h @@ -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 header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIBC_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_FCNTL_H 1 + +/* Define if you have the header file */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file */ +#undef HAVE_SYS_VFS_H + +/* Define if you have the header file */ +#undef HAVE_SYS_STATFS_H + +/* Define if you have the header file */ +#undef HAVE_SYS_STATVFS_H + +/* Define if you have the header file */ +#undef HAVE_POLL_H + +/* Define if you have the header file */ +#undef HAVE_SYS_POLL_H + +/* Define if you have the header file */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_FILIO_H 1 + +/* Define if you have the header file */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file */ +#undef HAVE_WINDOWS_H + +/* Define if you have the header file */ +#undef HAVE_WINSOCK_H + +/* Define if you have the header file */ +#undef HAVE_WINDOWS32_SOCKETS_H + +/* Define if you have the header file */ +#define HAVE_PWD_H 1 + +/* Define if you have the header file */ +#undef HAVE_PROCESS_H + +/* Define if you have the header file */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file */ +#define HAVE_TIME_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file */ +#define HAVE_UTIME_H 1 + +/* Define if you have the 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 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 +#endif +#if HAVE_SYS_POLL_H +# include +#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 index 00000000..49a10b1a --- /dev/null +++ b/skyrix-core/NGiCal/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/NGiCal/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-core/NGiCal/COPYRIGHT @@ -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 index 00000000..c78f6432 --- /dev/null +++ b/skyrix-core/NGiCal/ChangeLog @@ -0,0 +1,129 @@ +2004-08-14 Helge Hess + + * 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 + + * iCalEvent.h: moved 'status' field to iCalEntityObject, because it is + also available in todo objects (v4.2.23) + +2004-06-30 Marcus Mueller + + * 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 + + * v4.2.21 + + * GNUmakefile.preamble: added prebinding + + * GNUmakefile: create GNUmakefile.preamble, GNUmakefile.postamble + +2004-05-05 Marcus Mueller + + * 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 + + * iCalDataSource.m: added some sanity checks, improved to work better + with Mozilla generated iCal files (v4.2.19) + +2003-12-22 Helge Hess + + * iCalDateHolder.m: small fix not to print a warning for "YYYYMMDD" + style dates (which are supported) (v4.2.18) + +2003-12-21 Helge Hess + + * 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 + + * iCalDateHolder.m: added timeless date format: YYYYMMDD + (solves ogo bug 424) (v4.2.16) + +Wed Oct 29 22:04:32 2003 Martin Hoerning + + * 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 + + * GNUmakefile (libNGiCal_LIBRARIES_DEPEND_UPON): link against + libSaxObjC on MacOSX (v4.2.14) + +Fri Jul 18 17:04:55 2003 Martin Hoerning + + * iCalToDo.h, iCalPerson.h, iCalEvent.h, iCalEntityObject.h: added + accessor-methods to interface (v4.2.13) + +2003-07-18 Helge Hess + + * iCalDateHolder.m: replaces and indexOfString with rangeOfString, + thanks to Filip Van Raemdonck for pointing that out (v4.2.12) + +2003-03-21 Helge Hess + + * added some method prototypes + +2003-03-13 Helge Hess + + * moved iCalEntityObject to a separate file (v4.2.11) + +Mon Mar 10 18:41:10 2003 Bjoern Stierand + + * NGiCal.xmap: added missing attendee attributes (as dictated by + mh on the phone) + +2003-03-10 Helge Hess + + * iCalPerson.h: added some method prototypes + +2003-02-24 Helge Hess + + * iCalObject.h: added some accessors (v4.2.10) + +2003-02-12 Helge Hess + + * moved to skyrix-core (v4.2.9) + +2003-01-13 Helge Hess + + * added some support for timezones to be able to parse Evolution + apt creation requests (v4.2.7) + +2002-10-14 Helge Hess + + * 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 + + * ICalParser.m: small cleanups (v4.2.2) + +2002-10-04 Helge Hess + + * created ChangeLog, created NGiCal library into SkyCore + + diff --git a/skyrix-core/NGiCal/GNUmakefile b/skyrix-core/NGiCal/GNUmakefile new file mode 100644 index 00000000..3b536f0a --- /dev/null +++ b/skyrix-core/NGiCal/GNUmakefile @@ -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 index 00000000..8a7e1591 --- /dev/null +++ b/skyrix-core/NGiCal/GNUmakefile.postamble @@ -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 index 00000000..b255f0f4 --- /dev/null +++ b/skyrix-core/NGiCal/GNUmakefile.preamble @@ -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 index 00000000..c5c17a88 --- /dev/null +++ b/skyrix-core/NGiCal/IcalElements.m @@ -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 + +@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 index 00000000..f414ecd5 --- /dev/null +++ b/skyrix-core/NGiCal/IcalResponse.h @@ -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 + +@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 index 00000000..fcc59911 --- /dev/null +++ b/skyrix-core/NGiCal/IcalResponse.m @@ -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 + +@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 index 00000000..7839cf98 --- /dev/null +++ b/skyrix-core/NGiCal/NGiCal-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGiCal + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.core.NGiCal + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/NGiCal/NGiCal.h b/skyrix-core/NGiCal/NGiCal.h new file mode 100644 index 00000000..5d4e21c1 --- /dev/null +++ b/skyrix-core/NGiCal/NGiCal.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __NGiCal_H__ */ diff --git a/skyrix-core/NGiCal/NGiCal.xmap b/skyrix-core/NGiCal/NGiCal.xmap new file mode 100644 index 00000000..8e7a4546 --- /dev/null +++ b/skyrix-core/NGiCal/NGiCal.xmap @@ -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 index 00000000..fc95cc62 --- /dev/null +++ b/skyrix-core/NGiCal/NSCalendarDate+ICal.h @@ -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 + +@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 index 00000000..dabe0f0f --- /dev/null +++ b/skyrix-core/NGiCal/NSCalendarDate+ICal.m @@ -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 index 00000000..f65cf175 --- /dev/null +++ b/skyrix-core/NGiCal/NSString+ICal.h @@ -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 + +@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 index 00000000..b56593da --- /dev/null +++ b/skyrix-core/NGiCal/NSString+ICal.m @@ -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 + +@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 index 00000000..df050b77 --- /dev/null +++ b/skyrix-core/NGiCal/README @@ -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 index 00000000..a281cca1 --- /dev/null +++ b/skyrix-core/NGiCal/Version @@ -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 index 00000000..1633aa18 --- /dev/null +++ b/skyrix-core/NGiCal/common.h @@ -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 +#include +#include + +#endif /* __ICal_common_H__ */ diff --git a/skyrix-core/NGiCal/iCalAlarm.h b/skyrix-core/NGiCal/iCalAlarm.h new file mode 100644 index 00000000..766b0217 --- /dev/null +++ b/skyrix-core/NGiCal/iCalAlarm.h @@ -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 + +@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 index 00000000..6cf095b4 --- /dev/null +++ b/skyrix-core/NGiCal/iCalAlarm.m @@ -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 index 00000000..5b6a3717 --- /dev/null +++ b/skyrix-core/NGiCal/iCalAttachment.h @@ -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 + +@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 index 00000000..9a3edafc --- /dev/null +++ b/skyrix-core/NGiCal/iCalAttachment.m @@ -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 index 00000000..38c67461 --- /dev/null +++ b/skyrix-core/NGiCal/iCalCalendar.h @@ -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 + +@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 index 00000000..af41f390 --- /dev/null +++ b/skyrix-core/NGiCal/iCalCalendar.m @@ -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 index 00000000..f82f3aaf --- /dev/null +++ b/skyrix-core/NGiCal/iCalDataSource.h @@ -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 + +@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 index 00000000..9257e414 --- /dev/null +++ b/skyrix-core/NGiCal/iCalDataSource.m @@ -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 +#include "common.h" + +@interface NSObject(suppressCapitalizedKeyWarning) ++ (void)suppressCapitalizedKeyWarning; +@end + +@implementation iCalDataSource + +// THREAD +static id 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)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 index 00000000..d333c3e3 --- /dev/null +++ b/skyrix-core/NGiCal/iCalDateHolder.h @@ -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 + +@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 index 00000000..540e8e58 --- /dev/null +++ b/skyrix-core/NGiCal/iCalDateHolder.m @@ -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 index 00000000..7efa775f --- /dev/null +++ b/skyrix-core/NGiCal/iCalDuration.h @@ -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 + +@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 index 00000000..fd1e0d46 --- /dev/null +++ b/skyrix-core/NGiCal/iCalDuration.m @@ -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 index 00000000..fa30b25a --- /dev/null +++ b/skyrix-core/NGiCal/iCalEntityObject.h @@ -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 + +/* + 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 index 00000000..297b8a1d --- /dev/null +++ b/skyrix-core/NGiCal/iCalEntityObject.m @@ -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 index 00000000..1559038f --- /dev/null +++ b/skyrix-core/NGiCal/iCalEvent.h @@ -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 +#import + +/* + 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 index 00000000..b97cbc13 --- /dev/null +++ b/skyrix-core/NGiCal/iCalEvent.m @@ -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 index 00000000..06f96796 --- /dev/null +++ b/skyrix-core/NGiCal/iCalFreeBusy.h @@ -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 + +@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 index 00000000..1c8b330a --- /dev/null +++ b/skyrix-core/NGiCal/iCalFreeBusy.m @@ -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 index 00000000..007380c1 --- /dev/null +++ b/skyrix-core/NGiCal/iCalJournal.h @@ -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 + +@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 index 00000000..b81b647e --- /dev/null +++ b/skyrix-core/NGiCal/iCalJournal.m @@ -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 index 00000000..0ed2228b --- /dev/null +++ b/skyrix-core/NGiCal/iCalObject.h @@ -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 +#import + +/* + 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 index 00000000..f31ac094 --- /dev/null +++ b/skyrix-core/NGiCal/iCalObject.m @@ -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 index 00000000..7b670c70 --- /dev/null +++ b/skyrix-core/NGiCal/iCalPerson.h @@ -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 + +@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 index 00000000..a537156e --- /dev/null +++ b/skyrix-core/NGiCal/iCalPerson.m @@ -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 index 00000000..8d54e116 --- /dev/null +++ b/skyrix-core/NGiCal/iCalToDo.h @@ -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 + +/* + 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 index 00000000..7fb58bbb --- /dev/null +++ b/skyrix-core/NGiCal/iCalToDo.m @@ -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 index 00000000..7479a02d --- /dev/null +++ b/skyrix-core/NGiCal/iCalTrigger.h @@ -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 + +@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 index 00000000..32b3d4d4 --- /dev/null +++ b/skyrix-core/NGiCal/iCalTrigger.m @@ -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 index 00000000..ab0c70ac --- /dev/null +++ b/skyrix-core/PROJECTLEAD @@ -0,0 +1,3 @@ +# $Id$ + +PROJECTLEAD=helge.hess@opengroupware.org diff --git a/skyrix-core/README b/skyrix-core/README new file mode 100644 index 00000000..05c3ee22 --- /dev/null +++ b/skyrix-core/README @@ -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 index 00000000..c722ff36 --- /dev/null +++ b/skyrix-core/README-OSX.txt @@ -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 . + + +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 index 00000000..d90ae9f1 --- /dev/null +++ b/skyrix-core/SxCore-Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + SxCore + CFBundleIdentifier + org.OpenGroupware.SOPE.SxCore + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-core/SxCore.xcode/project.pbxproj b/skyrix-core/SxCore.xcode/project.pbxproj new file mode 100644 index 00000000..12a7a16e --- /dev/null +++ b/skyrix-core/SxCore.xcode/project.pbxproj @@ -0,0 +1,12995 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + AD0CE00A05D950D9004D9B87 = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = text; + path = ChangeLog; + refType = 4; + sourceTree = ""; + tabWidth = 4; + usesTabs = 1; + }; + AD16270E05D91F6300A7368D = { + fileEncoding = 5; + isa = PBXFileReference; + lastKnownFileType = text; + path = "README-OSX.txt"; + refType = 4; + sourceTree = ""; + }; + AD16271C05D934F700A7368D = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = Foundation.framework; + path = /System/Library/Frameworks/Foundation.framework; + refType = 0; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + AD1803270611DE9B00ED723F = { + fileRef = AD1803260611DE9B00ED723F; + isa = PBXBuildFile; + settings = { + }; + }; + AD1803280611DEFE00ED723F = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+German.h"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + AD73C3FA06D10BAD00226A2D = { + fileRef = AD73C3F906D10BAD00226A2D; + isa = PBXBuildFile; + settings = { + }; + }; + AD73C3FB06D10BDF00226A2D = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGCalendarDateRange.h; + refType = 4; + sourceTree = ""; + }; + AD73C3FC06D10BDF00226A2D = { + fileRef = AD73C3FB06D10BDF00226A2D; + isa = PBXBuildFile; + settings = { + }; + }; + AD853AA506A7F7F300727CA0 = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = LDAP.framework; + path = /System/Library/Frameworks/LDAP.framework; + refType = 0; + sourceTree = ""; + }; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + SxCore + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.SxCore + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = ""; + }; + 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 = ""; + }; +//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 = ""; + }; + E80D72AC05D6BA6E0050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessageMultipartBodyGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72AD05D6BA6E0050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessageRfc822BodyGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72AE05D6BA6E0050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessageTextBodyGenerator.m; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E80D72C905D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeContentDispositionHeaderFieldGenerator.m; + path = NGMime/NGMimeContentDispositionHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72CA05D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeContentLengthHeaderFieldGenerator.m; + path = NGMime/NGMimeContentLengthHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72CB05D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeContentTypeHeaderFieldGenerator.m; + path = NGMime/NGMimeContentTypeHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72CC05D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeHeaderFieldGeneratorSet.m; + path = NGMime/NGMimeHeaderFieldGeneratorSet.m; + refType = 4; + sourceTree = ""; + }; + E80D72CD05D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeRFC822DateHeaderFieldGenerator.m; + path = NGMime/NGMimeRFC822DateHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + E80D72CE05D6BAB10050931F = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeStringHeaderFieldGenerator.m; + path = NGMime/NGMimeStringHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81BE23B055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = NGMime/common.h; + refType = 4; + sourceTree = ""; + }; + E81BE23C055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = NGMime/COPYING; + refType = 4; + sourceTree = ""; + }; + E81BE23D055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = NGMime/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81BE23E055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = NGMime/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81BE23F055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = NGMime/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E81BE240055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = libNGMime.def; + path = NGMime/libNGMime.def; + refType = 4; + sourceTree = ""; + }; + E81BE241055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGConcreteMimeType.h; + path = NGMime/NGConcreteMimeType.h; + refType = 4; + sourceTree = ""; + }; + E81BE242055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGConcreteMimeType.m; + path = NGMime/NGConcreteMimeType.m; + refType = 4; + sourceTree = ""; + }; + E81BE243055EDACF00B28141 = { + children = ( + E81BE280055EDAD100B28141, + E81BE247055EDACF00B28141, + E81BE244055EDACF00B28141, + E81BE245055EDACF00B28141, + E81BE4C0055EDC3600B28141, + E81BE4C3055EDC5B00B28141, + E81BE4C6055EDC6C00B28141, + ); + isa = PBXGroup; + name = NGImap4; + path = NGMime/NGImap4; + refType = 4; + sourceTree = ""; + }; + E81BE244055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81BE245055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = ChangeLog; + refType = 4; + sourceTree = ""; + }; + E81BE247055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = COPYING; + refType = 4; + sourceTree = ""; + }; + E81BE248055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81BE249055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4.h; + refType = 4; + sourceTree = ""; + }; + E81BE24A055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4.m; + refType = 4; + sourceTree = ""; + }; + E81BE24B055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Client.h; + refType = 4; + sourceTree = ""; + }; + E81BE24C055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Client.m; + refType = 4; + sourceTree = ""; + }; + E81BE24D055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Context.h; + refType = 4; + sourceTree = ""; + }; + E81BE24E055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Context.m; + refType = 4; + sourceTree = ""; + }; + E81BE24F055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4DataSource.h; + refType = 4; + sourceTree = ""; + }; + E81BE250055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4DataSource.m; + refType = 4; + sourceTree = ""; + }; + E81BE251055EDACF00B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4FileManager.h; + refType = 4; + sourceTree = ""; + }; + E81BE252055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4FileManager.m; + refType = 4; + sourceTree = ""; + }; + E81BE253055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Folder.h; + refType = 4; + sourceTree = ""; + }; + E81BE254055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Folder.m; + refType = 4; + sourceTree = ""; + }; + E81BE255055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Functions.h; + refType = 4; + sourceTree = ""; + }; + E81BE256055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Functions.m; + refType = 4; + sourceTree = ""; + }; + E81BE257055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NGImap4Message+BodyStructure.h"; + refType = 4; + sourceTree = ""; + }; + E81BE258055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Message.h; + refType = 4; + sourceTree = ""; + }; + E81BE259055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Message.m; + refType = 4; + sourceTree = ""; + }; + E81BE25A055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4ResponseParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE25B055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4ResponseParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE25C055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4ServerRoot.h; + refType = 4; + sourceTree = ""; + }; + E81BE25D055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4ServerRoot.m; + refType = 4; + sourceTree = ""; + }; + E81BE25E055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4Support.h; + refType = 4; + sourceTree = ""; + }; + E81BE25F055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4Support.m; + refType = 4; + sourceTree = ""; + }; + E81BE260055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSieveClient.h; + refType = 4; + sourceTree = ""; + }; + E81BE261055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGSieveClient.m; + refType = 4; + sourceTree = ""; + }; + E81BE262055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+Imap4.h"; + refType = 4; + sourceTree = ""; + }; + E81BE263055EDAD000B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+Imap4.m"; + refType = 4; + sourceTree = ""; + }; + E81BE280055EDAD100B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + E81BE29E055EDAD200B28141 = { + children = ( + E81BE2D9055EDAD300B28141, + E81BE2A2055EDAD200B28141, + E81BE2A0055EDAD200B28141, + E81BE29F055EDAD200B28141, + E81BE4C9055EDC7A00B28141, + E81BE4CC055EDCA000B28141, + E81BE4CF055EDCAC00B28141, + ); + isa = PBXGroup; + name = NGMail; + path = NGMime/NGMail; + refType = 4; + sourceTree = ""; + }; + E81BE29F055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81BE2A0055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = ChangeLog; + refType = 4; + sourceTree = ""; + }; + E81BE2A1055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = common.h; + refType = 4; + sourceTree = ""; + }; + E81BE2A2055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = COPYING; + refType = 4; + sourceTree = ""; + }; + E81BE2A3055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81BE2A4055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = libNGMail.def; + refType = 4; + sourceTree = ""; + }; + E81BE2A5055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMail.h; + refType = 4; + sourceTree = ""; + }; + E81BE2A6055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMail.m; + refType = 4; + sourceTree = ""; + }; + E81BE2A7055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMailAddress.h; + refType = 4; + sourceTree = ""; + }; + E81BE2A8055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMailAddress.m; + refType = 4; + sourceTree = ""; + }; + E81BE2A9055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMailAddressList.h; + refType = 4; + sourceTree = ""; + }; + E81BE2AA055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMailAddressList.m; + refType = 4; + sourceTree = ""; + }; + E81BE2AB055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMailAddressParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE2AC055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMailAddressParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE2AD055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMailDecls.h; + refType = 4; + sourceTree = ""; + }; + E81BE2AE055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMBoxReader.h; + refType = 4; + sourceTree = ""; + }; + E81BE2AF055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMBoxReader.m; + refType = 4; + sourceTree = ""; + }; + E81BE2B0055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMimeMessage.h; + refType = 4; + sourceTree = ""; + }; + E81BE2B1055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessage.m; + refType = 4; + sourceTree = ""; + }; + E81BE2B2055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMimeMessageGenerator.h; + refType = 4; + sourceTree = ""; + }; + E81BE2B3055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessageGenerator.m; + refType = 4; + sourceTree = ""; + }; + E81BE2B4055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMimeMessageParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE2B5055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGMimeMessageParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE2B6055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGPop3Client.h; + refType = 4; + sourceTree = ""; + }; + E81BE2B7055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGPop3Client.m; + refType = 4; + sourceTree = ""; + }; + E81BE2B8055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGPop3Support.h; + refType = 4; + sourceTree = ""; + }; + E81BE2B9055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGPop3Support.m; + refType = 4; + sourceTree = ""; + }; + E81BE2BA055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSmtpClient.h; + refType = 4; + sourceTree = ""; + }; + E81BE2BB055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGSmtpClient.m; + refType = 4; + sourceTree = ""; + }; + E81BE2BC055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSmtpReplyCodes.h; + refType = 4; + sourceTree = ""; + }; + E81BE2BD055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSmtpSupport.h; + refType = 4; + sourceTree = ""; + }; + E81BE2BE055EDAD200B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGSmtpSupport.m; + refType = 4; + sourceTree = ""; + }; + E81BE2D9055EDAD300B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + E81BE2F4055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.plist; + name = "NGMime-Info.plist"; + path = "NGMime/NGMime-Info.plist"; + refType = 4; + sourceTree = ""; + }; + E81BE2F5055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMime.h; + path = NGMime/NGMime.h; + refType = 4; + sourceTree = ""; + }; + E81BE2F6055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMime.m; + path = NGMime/NGMime.m; + refType = 4; + sourceTree = ""; + }; + E81BE2F7055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeBodyGenerator.h; + path = NGMime/NGMimeBodyGenerator.h; + refType = 4; + sourceTree = ""; + }; + E81BE2F8055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeBodyGenerator.m; + path = NGMime/NGMimeBodyGenerator.m; + refType = 4; + sourceTree = ""; + }; + E81BE2F9055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeBodyParser.h; + path = NGMime/NGMimeBodyParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE2FA055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeBodyParser.m; + path = NGMime/NGMimeBodyParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE2FB055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeBodyPart.h; + path = NGMime/NGMimeBodyPart.h; + refType = 4; + sourceTree = ""; + }; + E81BE2FC055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeBodyPart.m; + path = NGMime/NGMimeBodyPart.m; + refType = 4; + sourceTree = ""; + }; + E81BE2FD055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeBodyPartParser.h; + path = NGMime/NGMimeBodyPartParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE2FE055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeBodyPartParser.m; + path = NGMime/NGMimeBodyPartParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE2FF055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeDecls.h; + path = NGMime/NGMimeDecls.h; + refType = 4; + sourceTree = ""; + }; + E81BE300055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeExceptions.h; + path = NGMime/NGMimeExceptions.h; + refType = 4; + sourceTree = ""; + }; + E81BE301055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeExceptions.m; + path = NGMime/NGMimeExceptions.m; + refType = 4; + sourceTree = ""; + }; + E81BE302055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeFileData.h; + path = NGMime/NGMimeFileData.h; + refType = 4; + sourceTree = ""; + }; + E81BE303055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeFileData.m; + path = NGMime/NGMimeFileData.m; + refType = 4; + sourceTree = ""; + }; + E81BE304055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeGeneratorProtocols.h; + path = NGMime/NGMimeGeneratorProtocols.h; + refType = 4; + sourceTree = ""; + }; + E81BE305055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeHeaderFieldGenerator.h; + path = NGMime/NGMimeHeaderFieldGenerator.h; + refType = 4; + sourceTree = ""; + }; + E81BE306055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeHeaderFieldGenerator.m; + path = NGMime/NGMimeHeaderFieldGenerator.m; + refType = 4; + sourceTree = ""; + }; + E81BE307055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeHeaderFieldParser.h; + path = NGMime/NGMimeHeaderFieldParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE308055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeHeaderFieldParser.m; + path = NGMime/NGMimeHeaderFieldParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE309055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeHeaderFields.h; + path = NGMime/NGMimeHeaderFields.h; + refType = 4; + sourceTree = ""; + }; + E81BE30A055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeHeaderFields.m; + path = NGMime/NGMimeHeaderFields.m; + refType = 4; + sourceTree = ""; + }; + E81BE30B055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeJoinedData.h; + path = NGMime/NGMimeJoinedData.h; + refType = 4; + sourceTree = ""; + }; + E81BE30C055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeJoinedData.m; + path = NGMime/NGMimeJoinedData.m; + refType = 4; + sourceTree = ""; + }; + E81BE30D055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeMultipartBody.h; + path = NGMime/NGMimeMultipartBody.h; + refType = 4; + sourceTree = ""; + }; + E81BE30E055EDAD400B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeMultipartBody.m; + path = NGMime/NGMimeMultipartBody.m; + refType = 4; + sourceTree = ""; + }; + E81BE30F055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeMultipartBodyParser.m; + path = NGMime/NGMimeMultipartBodyParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE310055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimePartGenerator.h; + path = NGMime/NGMimePartGenerator.h; + refType = 4; + sourceTree = ""; + }; + E81BE311055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimePartGenerator.m; + path = NGMime/NGMimePartGenerator.m; + refType = 4; + sourceTree = ""; + }; + E81BE312055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimePartParser.h; + path = NGMime/NGMimePartParser.h; + refType = 4; + sourceTree = ""; + }; + E81BE313055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimePartParser.m; + path = NGMime/NGMimePartParser.m; + refType = 4; + sourceTree = ""; + }; + E81BE314055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeType.h; + path = NGMime/NGMimeType.h; + refType = 4; + sourceTree = ""; + }; + E81BE315055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeType.m; + path = NGMime/NGMimeType.m; + refType = 4; + sourceTree = ""; + }; + E81BE316055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGMimeUtilities.h; + path = NGMime/NGMimeUtilities.h; + refType = 4; + sourceTree = ""; + }; + E81BE317055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeUtilities.m; + path = NGMime/NGMimeUtilities.m; + refType = 4; + sourceTree = ""; + }; + E81BE318055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGPart.h; + path = NGMime/NGPart.h; + refType = 4; + sourceTree = ""; + }; + E81BE319055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGPart.m; + path = NGMime/NGPart.m; + refType = 4; + sourceTree = ""; + }; + E81BE31A055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = NGMime/README; + refType = 4; + sourceTree = ""; + }; + E81BE31B055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = "SxCore-NGMime.graffle"; + path = "NGMime/SxCore-NGMime.graffle"; + refType = 4; + sourceTree = ""; + }; + E81BE31C055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = timeMacros.h; + path = NGMime/timeMacros.h; + refType = 4; + sourceTree = ""; + }; + E81BE31D055EDAD500B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = NGMime/Version; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81BE3FF055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = NGLdap/common.h; + refType = 4; + sourceTree = ""; + }; + E81BE400055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = NGLdap/COPYING; + refType = 4; + sourceTree = ""; + }; + E81BE401055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = NGLdap/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81BE402055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "EOQualifier+LDAP.h"; + path = "NGLdap/EOQualifier+LDAP.h"; + refType = 4; + sourceTree = ""; + }; + E81BE403055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "EOQualifier+LDAP.m"; + path = "NGLdap/EOQualifier+LDAP.m"; + refType = 4; + sourceTree = ""; + }; + E81BE404055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = NGLdap/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81BE405055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.postamble; + path = NGLdap/GNUmakefile.postamble; + refType = 4; + sourceTree = ""; + }; + E81BE406055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = NGLdap/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E81BE407055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.plist; + name = "NGLdap-Info.plist"; + path = "NGLdap/NGLdap-Info.plist"; + refType = 4; + sourceTree = ""; + }; + E81BE408055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdap.h; + path = NGLdap/NGLdap.h; + refType = 4; + sourceTree = ""; + }; + E81BE409055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapAttribute.h; + path = NGLdap/NGLdapAttribute.h; + refType = 4; + sourceTree = ""; + }; + E81BE40A055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapAttribute.m; + path = NGLdap/NGLdapAttribute.m; + refType = 4; + sourceTree = ""; + }; + E81BE40B055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapConnection.h; + path = NGLdap/NGLdapConnection.h; + refType = 4; + sourceTree = ""; + }; + E81BE40C055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapConnection.m; + path = NGLdap/NGLdapConnection.m; + refType = 4; + sourceTree = ""; + }; + E81BE40D055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NGLdapConnection+Private.h"; + path = "NGLdap/NGLdapConnection+Private.h"; + refType = 4; + sourceTree = ""; + }; + E81BE40E055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapDataSource.h; + path = NGLdap/NGLdapDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81BE40F055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapDataSource.m; + path = NGLdap/NGLdapDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81BE410055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapEntry.h; + path = NGLdap/NGLdapEntry.h; + refType = 4; + sourceTree = ""; + }; + E81BE411055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapEntry.m; + path = NGLdap/NGLdapEntry.m; + refType = 4; + sourceTree = ""; + }; + E81BE412055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapFileManager.h; + path = NGLdap/NGLdapFileManager.h; + refType = 4; + sourceTree = ""; + }; + E81BE413055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapFileManager.m; + path = NGLdap/NGLdapFileManager.m; + refType = 4; + sourceTree = ""; + }; + E81BE414055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapGlobalID.h; + path = NGLdap/NGLdapGlobalID.h; + refType = 4; + sourceTree = ""; + }; + E81BE415055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapGlobalID.m; + path = NGLdap/NGLdapGlobalID.m; + refType = 4; + sourceTree = ""; + }; + E81BE416055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapModification.h; + path = NGLdap/NGLdapModification.h; + refType = 4; + sourceTree = ""; + }; + E81BE417055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapModification.m; + path = NGLdap/NGLdapModification.m; + refType = 4; + sourceTree = ""; + }; + E81BE418055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapSearchResultEnumerator.h; + path = NGLdap/NGLdapSearchResultEnumerator.h; + refType = 4; + sourceTree = ""; + }; + E81BE419055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapSearchResultEnumerator.m; + path = NGLdap/NGLdapSearchResultEnumerator.m; + refType = 4; + sourceTree = ""; + }; + E81BE41A055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGLdapURL.h; + path = NGLdap/NGLdapURL.h; + refType = 4; + sourceTree = ""; + }; + E81BE41B055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLdapURL.m; + path = NGLdap/NGLdapURL.m; + refType = 4; + sourceTree = ""; + }; + E81BE41C055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSString+DN.h"; + path = "NGLdap/NSString+DN.h"; + refType = 4; + sourceTree = ""; + }; + E81BE41D055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSString+DN.m"; + path = "NGLdap/NSString+DN.m"; + refType = 4; + sourceTree = ""; + }; + E81BE41E055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = NGLdap/README; + refType = 4; + sourceTree = ""; + }; + E81BE41F055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README.macosx; + path = NGLdap/README.macosx; + refType = 4; + sourceTree = ""; + }; + E81BE420055EDAF900B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = NGLdap/Version; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81BE449055EDB1E00B28141 = { + children = ( + E81BE402055EDAF900B28141, + E81BE408055EDAF900B28141, + E81BE409055EDAF900B28141, + E81BE40B055EDAF900B28141, + E81BE40D055EDAF900B28141, + E81BE40E055EDAF900B28141, + E81BE410055EDAF900B28141, + E81BE412055EDAF900B28141, + E81BE414055EDAF900B28141, + E81BE416055EDAF900B28141, + E81BE418055EDAF900B28141, + E81BE41A055EDAF900B28141, + E81BE41C055EDAF900B28141, + ); + isa = PBXGroup; + name = Headers; + refType = 4; + sourceTree = ""; + }; + E81BE44C055EDB2A00B28141 = { + children = ( + E81BE3FF055EDAF900B28141, + E81BE403055EDAF900B28141, + E81BE40A055EDAF900B28141, + E81BE40C055EDAF900B28141, + E81BE40F055EDAF900B28141, + E81BE411055EDAF900B28141, + E81BE413055EDAF900B28141, + E81BE415055EDAF900B28141, + E81BE417055EDAF900B28141, + E81BE419055EDAF900B28141, + E81BE41B055EDAF900B28141, + E81BE41D055EDAF900B28141, + ); + isa = PBXGroup; + name = Classes; + refType = 4; + sourceTree = ""; + }; + E81BE44F055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = ChangeLog; + path = NGiCal/ChangeLog; + refType = 4; + sourceTree = ""; + }; + E81BE450055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = NGiCal/common.h; + refType = 4; + sourceTree = ""; + }; + E81BE451055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = NGiCal/COPYING; + refType = 4; + sourceTree = ""; + }; + E81BE452055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = NGiCal/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81BE453055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = NGiCal/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81BE454055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalAlarm.h; + path = NGiCal/iCalAlarm.h; + refType = 4; + sourceTree = ""; + }; + E81BE455055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalAlarm.m; + path = NGiCal/iCalAlarm.m; + refType = 4; + sourceTree = ""; + }; + E81BE456055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalAttachment.h; + path = NGiCal/iCalAttachment.h; + refType = 4; + sourceTree = ""; + }; + E81BE457055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalAttachment.m; + path = NGiCal/iCalAttachment.m; + refType = 4; + sourceTree = ""; + }; + E81BE458055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalCalendar.h; + path = NGiCal/iCalCalendar.h; + refType = 4; + sourceTree = ""; + }; + E81BE459055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalCalendar.m; + path = NGiCal/iCalCalendar.m; + refType = 4; + sourceTree = ""; + }; + E81BE45A055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalDataSource.h; + path = NGiCal/iCalDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81BE45B055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalDataSource.m; + path = NGiCal/iCalDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81BE45C055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalDateHolder.h; + path = NGiCal/iCalDateHolder.h; + refType = 4; + sourceTree = ""; + }; + E81BE45D055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalDateHolder.m; + path = NGiCal/iCalDateHolder.m; + refType = 4; + sourceTree = ""; + }; + E81BE45E055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalDuration.h; + path = NGiCal/iCalDuration.h; + refType = 4; + sourceTree = ""; + }; + E81BE45F055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalDuration.m; + path = NGiCal/iCalDuration.m; + refType = 4; + sourceTree = ""; + }; + E81BE460055EDB5600B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = IcalElements.m; + path = NGiCal/IcalElements.m; + refType = 4; + sourceTree = ""; + }; + E81BE461055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalEntityObject.h; + path = NGiCal/iCalEntityObject.h; + refType = 4; + sourceTree = ""; + }; + E81BE462055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalEntityObject.m; + path = NGiCal/iCalEntityObject.m; + refType = 4; + sourceTree = ""; + }; + E81BE463055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalEvent.h; + path = NGiCal/iCalEvent.h; + refType = 4; + sourceTree = ""; + }; + E81BE464055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalEvent.m; + path = NGiCal/iCalEvent.m; + refType = 4; + sourceTree = ""; + }; + E81BE465055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalFreeBusy.h; + path = NGiCal/iCalFreeBusy.h; + refType = 4; + sourceTree = ""; + }; + E81BE466055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalFreeBusy.m; + path = NGiCal/iCalFreeBusy.m; + refType = 4; + sourceTree = ""; + }; + E81BE467055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalJournal.h; + path = NGiCal/iCalJournal.h; + refType = 4; + sourceTree = ""; + }; + E81BE468055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalJournal.m; + path = NGiCal/iCalJournal.m; + refType = 4; + sourceTree = ""; + }; + E81BE469055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalObject.h; + path = NGiCal/iCalObject.h; + refType = 4; + sourceTree = ""; + }; + E81BE46A055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalObject.m; + path = NGiCal/iCalObject.m; + refType = 4; + sourceTree = ""; + }; + E81BE46B055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalPerson.h; + path = NGiCal/iCalPerson.h; + refType = 4; + sourceTree = ""; + }; + E81BE46C055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalPerson.m; + path = NGiCal/iCalPerson.m; + refType = 4; + sourceTree = ""; + }; + E81BE46D055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = IcalResponse.h; + path = NGiCal/IcalResponse.h; + refType = 4; + sourceTree = ""; + }; + E81BE46E055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = IcalResponse.m; + path = NGiCal/IcalResponse.m; + refType = 4; + sourceTree = ""; + }; + E81BE46F055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalToDo.h; + path = NGiCal/iCalToDo.h; + refType = 4; + sourceTree = ""; + }; + E81BE470055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalToDo.m; + path = NGiCal/iCalToDo.m; + refType = 4; + sourceTree = ""; + }; + E81BE471055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = iCalTrigger.h; + path = NGiCal/iCalTrigger.h; + refType = 4; + sourceTree = ""; + }; + E81BE472055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = iCalTrigger.m; + path = NGiCal/iCalTrigger.m; + refType = 4; + sourceTree = ""; + }; + E81BE473055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.plist; + name = "NGiCal-Info.plist"; + path = "NGiCal/NGiCal-Info.plist"; + refType = 4; + sourceTree = ""; + }; + E81BE474055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NGiCal.h; + path = NGiCal/NGiCal.h; + refType = 4; + sourceTree = ""; + }; + E81BE475055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = NGiCal.xmap; + path = NGiCal/NGiCal.xmap; + refType = 4; + sourceTree = ""; + }; + E81BE476055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSCalendarDate+ICal.h"; + path = "NGiCal/NSCalendarDate+ICal.h"; + refType = 4; + sourceTree = ""; + }; + E81BE477055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSCalendarDate+ICal.m"; + path = "NGiCal/NSCalendarDate+ICal.m"; + refType = 4; + sourceTree = ""; + }; + E81BE478055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSString+ICal.h"; + path = "NGiCal/NSString+ICal.h"; + refType = 4; + sourceTree = ""; + }; + E81BE479055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSString+ICal.m"; + path = "NGiCal/NSString+ICal.m"; + refType = 4; + sourceTree = ""; + }; + E81BE47A055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = NGiCal/README; + refType = 4; + sourceTree = ""; + }; + E81BE47B055EDB5700B28141 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = NGiCal/Version; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81BE4B4055EDBCB00B28141 = { + children = ( + E81BE23E055EDACF00B28141, + E81BE23F055EDACF00B28141, + E81BE240055EDACF00B28141, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81BE4BA055EDC0200B28141 = { + children = ( + E81BE31B055EDAD500B28141, + ); + isa = PBXGroup; + name = Documentation; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81BE4C0055EDC3600B28141 = { + children = ( + E81BE248055EDACF00B28141, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81BE4C9055EDC7A00B28141 = { + children = ( + E81BE2A3055EDAD200B28141, + E81BE2A4055EDAD200B28141, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + E81BE4CC055EDCA000B28141 = { + children = ( + E81BE2A5055EDAD200B28141, + E81BE2A7055EDAD200B28141, + E81BE2A9055EDAD200B28141, + E81BE2AB055EDAD200B28141, + E81BE2AD055EDAD200B28141, + E81BE2AE055EDAD200B28141, + E81BE2B0055EDAD200B28141, + E81BE2B2055EDAD200B28141, + E81BE2B4055EDAD200B28141, + E81BE2B6055EDAD200B28141, + E81BE2B8055EDAD200B28141, + E81BE2BA055EDAD200B28141, + E81BE2BC055EDAD200B28141, + E81BE2BD055EDAD200B28141, + ); + isa = PBXGroup; + name = Headers; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81E04B2055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = ChangeLog; + path = NGStreams/ChangeLog; + refType = 4; + sourceTree = ""; + }; + E81E04B3055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = NGStreams/common.h; + refType = 4; + sourceTree = ""; + }; + E81E04B4055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + name = config.guess; + path = NGStreams/config.guess; + refType = 4; + sourceTree = ""; + }; + E81E04B5055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = config.h.in; + path = NGStreams/config.h.in; + refType = 4; + sourceTree = ""; + }; + E81E04B6055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + name = config.sub; + path = NGStreams/config.sub; + refType = 4; + sourceTree = ""; + }; + E81E04B7055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + name = configure; + path = NGStreams/configure; + refType = 4; + sourceTree = ""; + }; + E81E04B8055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = configure.in; + path = NGStreams/configure.in; + refType = 4; + sourceTree = ""; + }; + E81E04B9055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = NGStreams/COPYING; + refType = 4; + sourceTree = ""; + }; + E81E04BA055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = NGStreams/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81E04BB055DE7E2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = DESIGN; + path = NGStreams/DESIGN; + refType = 4; + sourceTree = ""; + }; + E81E04BC055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = NGStreams/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81E04BD055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.postamble; + path = NGStreams/GNUmakefile.postamble; + refType = 4; + sourceTree = ""; + }; + E81E04BE055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = NGStreams/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E81E04BF055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.script.sh; + name = "install-sh"; + path = "NGStreams/install-sh"; + refType = 4; + sourceTree = ""; + }; + E81E04C0055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = libNGStreams.def; + path = NGStreams/libNGStreams.def; + refType = 4; + sourceTree = ""; + }; + E81E04C1055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGActiveSocket.m; + path = NGStreams/NGActiveSocket.m; + refType = 4; + sourceTree = ""; + }; + E81E04C2055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NGActiveSocket+serialization.m"; + path = "NGStreams/NGActiveSocket+serialization.m"; + refType = 4; + sourceTree = ""; + }; + E81E04C3055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGActiveSSLSocket.m; + path = NGStreams/NGActiveSSLSocket.m; + refType = 4; + sourceTree = ""; + }; + E81E04C4055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGBase64Stream.m; + path = NGStreams/NGBase64Stream.m; + refType = 4; + sourceTree = ""; + }; + E81E04C5055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGBufferedStream.m; + path = NGStreams/NGBufferedStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04C6055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGByteBuffer.m; + path = NGStreams/NGByteBuffer.m; + refType = 4; + sourceTree = ""; + }; + E81E04C7055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGByteCountStream.m; + path = NGStreams/NGByteCountStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04C8055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGCharBuffer.m; + path = NGStreams/NGCharBuffer.m; + refType = 4; + sourceTree = ""; + }; + E81E04C9055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGConcreteStreamFileHandle.m; + path = NGStreams/NGConcreteStreamFileHandle.m; + refType = 4; + sourceTree = ""; + }; + E81E04CA055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGCTextStream.m; + path = NGStreams/NGCTextStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04CB055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGDatagramPacket.m; + path = NGStreams/NGDatagramPacket.m; + refType = 4; + sourceTree = ""; + }; + E81E04CC055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGDatagramSocket.m; + path = NGStreams/NGDatagramSocket.m; + refType = 4; + sourceTree = ""; + }; + E81E04CD055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGDataStream.m; + path = NGStreams/NGDataStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04CE055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGDescriptorFunctions.m; + path = NGStreams/NGDescriptorFunctions.m; + refType = 4; + sourceTree = ""; + }; + E81E04CF055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFileStream.m; + path = NGStreams/NGFileStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04D0055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFilterStream.m; + path = NGStreams/NGFilterStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04D1055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFilterTextStream.m; + path = NGStreams/NGFilterTextStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04D2055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGGZipStream.m; + path = NGStreams/NGGZipStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04D3055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGInternetSocketAddress.m; + path = NGStreams/NGInternetSocketAddress.m; + refType = 4; + sourceTree = ""; + }; + E81E04D4055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGInternetSocketDomain.m; + path = NGStreams/NGInternetSocketDomain.m; + refType = 4; + sourceTree = ""; + }; + E81E04D5055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLocalSocketAddress.m; + path = NGStreams/NGLocalSocketAddress.m; + refType = 4; + sourceTree = ""; + }; + E81E04D6055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLocalSocketDomain.m; + path = NGStreams/NGLocalSocketDomain.m; + refType = 4; + sourceTree = ""; + }; + E81E04D7055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGLockingStream.m; + path = NGStreams/NGLockingStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04D8055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGNetUtilities.m; + path = NGStreams/NGNetUtilities.m; + refType = 4; + sourceTree = ""; + }; + E81E04D9055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGPassiveSocket.m; + path = NGStreams/NGPassiveSocket.m; + refType = 4; + sourceTree = ""; + }; + E81E04DA055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGSocket.m; + path = NGStreams/NGSocket.m; + refType = 4; + sourceTree = ""; + }; + E81E04DB055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NGSocket+private.h"; + path = "NGStreams/NGSocket+private.h"; + refType = 4; + sourceTree = ""; + }; + E81E04DC055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGSocketExceptions.m; + path = NGStreams/NGSocketExceptions.m; + refType = 4; + sourceTree = ""; + }; + E81E04DD055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStream.m; + path = NGStreams/NGStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04DE055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NGStream+serialization.m"; + path = "NGStreams/NGStream+serialization.m"; + refType = 4; + sourceTree = ""; + }; + E81E04DF055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStreamCoder.m; + path = NGStreams/NGStreamCoder.m; + refType = 4; + sourceTree = ""; + }; + E81E04E0055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStreamExceptions.m; + path = NGStreams/NGStreamExceptions.m; + refType = 4; + sourceTree = ""; + }; + E81E04E1055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStreamPipe.m; + path = NGStreams/NGStreamPipe.m; + refType = 4; + sourceTree = ""; + }; + E81E04E2055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStreams.m; + path = NGStreams/NGStreams.m; + refType = 4; + sourceTree = ""; + }; + E81E04E3055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStringTextStream.m; + path = NGStreams/NGStringTextStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04E4055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGTaskStream.m; + path = NGStreams/NGTaskStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04E5055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGTerminalSupport.m; + path = NGStreams/NGTerminalSupport.m; + refType = 4; + sourceTree = ""; + }; + E81E04E6055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGTextStream.m; + path = NGStreams/NGTextStream.m; + refType = 4; + sourceTree = ""; + }; + E81E04E7055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = NGStreams/README; + refType = 4; + sourceTree = ""; + }; + E81E04E8055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = "SxCore-NGStreams.graffle"; + path = "NGStreams/SxCore-NGStreams.graffle"; + refType = 4; + sourceTree = ""; + }; + E81E04E9055DE7E3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = NGStreams/Version; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81E052A055DE833006FE529 = { + children = ( + E81E04BB055DE7E2006FE529, + E81E04E8055DE7E3006FE529, + ); + isa = PBXGroup; + name = Documentation; + refType = 4; + sourceTree = ""; + }; + E81E05C9055DE8B2006FE529 = { + children = ( + E81E05CA055DE8B2006FE529, + ); + isa = PBXGroup; + name = macosx; + path = NGStreams/macosx; + refType = 4; + sourceTree = ""; + }; + E81E05CA055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = config.h; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81E05CC055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NGActiveSocket+serialization.h"; + refType = 4; + sourceTree = ""; + }; + E81E05CD055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGActiveSocket.h; + refType = 4; + sourceTree = ""; + }; + E81E05CE055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGActiveSSLSocket.h; + refType = 4; + sourceTree = ""; + }; + E81E05CF055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBase64Stream.h; + refType = 4; + sourceTree = ""; + }; + E81E05D0055DE8B2006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBufferedStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05D1055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGByteBuffer.h; + refType = 4; + sourceTree = ""; + }; + E81E05D2055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGByteCountStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05D3055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGCharBuffer.h; + refType = 4; + sourceTree = ""; + }; + E81E05D4055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGConcreteStreamFileHandle.h; + refType = 4; + sourceTree = ""; + }; + E81E05D5055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGCTextStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05D6055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGDatagramPacket.h; + refType = 4; + sourceTree = ""; + }; + E81E05D7055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGDatagramSocket.h; + refType = 4; + sourceTree = ""; + }; + E81E05D8055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGDataStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05D9055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGDescriptorFunctions.h; + refType = 4; + sourceTree = ""; + }; + E81E05DA055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFileStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05DB055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFilterStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05DC055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFilterTextStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05DD055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGGZipStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05DE055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGInternetSocketAddress.h; + refType = 4; + sourceTree = ""; + }; + E81E05DF055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGInternetSocketDomain.h; + refType = 4; + sourceTree = ""; + }; + E81E05E0055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGLocalSocketAddress.h; + refType = 4; + sourceTree = ""; + }; + E81E05E1055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGLocalSocketDomain.h; + refType = 4; + sourceTree = ""; + }; + E81E05E2055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGLockingStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05E3055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGNet.h; + refType = 4; + sourceTree = ""; + }; + E81E05E4055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGNetDecls.h; + refType = 4; + sourceTree = ""; + }; + E81E05E5055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGNetUtilities.h; + refType = 4; + sourceTree = ""; + }; + E81E05E6055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGPassiveSocket.h; + refType = 4; + sourceTree = ""; + }; + E81E05E7055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSocket.h; + refType = 4; + sourceTree = ""; + }; + E81E05E8055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSocketExceptions.h; + refType = 4; + sourceTree = ""; + }; + E81E05E9055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGSocketProtocols.h; + refType = 4; + sourceTree = ""; + }; + E81E05EA055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NGStream+serialization.h"; + refType = 4; + sourceTree = ""; + }; + E81E05EB055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05EC055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreamCoder.h; + refType = 4; + sourceTree = ""; + }; + E81E05ED055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreamExceptions.h; + refType = 4; + sourceTree = ""; + }; + E81E05EE055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreamPipe.h; + refType = 4; + sourceTree = ""; + }; + E81E05EF055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreamProtocols.h; + refType = 4; + sourceTree = ""; + }; + E81E05F0055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreams.h; + refType = 4; + sourceTree = ""; + }; + E81E05F1055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStreamsDecls.h; + refType = 4; + sourceTree = ""; + }; + E81E05F2055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStringTextStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05F3055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGTaskStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05F4055DE8B3006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGTerminalSupport.h; + refType = 4; + sourceTree = ""; + }; + E81E05F5055DE8B4006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGTextStream.h; + refType = 4; + sourceTree = ""; + }; + E81E05F6055DE8B4006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGTextStreamProtocols.h; + refType = 4; + sourceTree = ""; + }; + E81E05F7055DE8B4006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGUrlChars.h; + refType = 4; + sourceTree = ""; + }; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGLdap + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGLdap + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = ""; + }; + E81E06C3055E6EC6006FE529 = { + children = ( + E81E04C1055DE7E3006FE529, + E81E04C3055DE7E3006FE529, + E81E04CB055DE7E3006FE529, + E81E04CC055DE7E3006FE529, + E81E04D3055DE7E3006FE529, + E81E04D4055DE7E3006FE529, + E81E04D5055DE7E3006FE529, + E81E04D6055DE7E3006FE529, + E81E04D8055DE7E3006FE529, + E81E04D9055DE7E3006FE529, + E81E04DA055DE7E3006FE529, + E81E04DB055DE7E3006FE529, + E81E04DC055DE7E3006FE529, + ); + isa = PBXGroup; + name = Network; + path = ""; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81EF5D3055DC9E0006FE529 = { + children = ( + E81BE31A055EDAD500B28141, + E81BE23A055EDACF00B28141, + E81BE23C055EDACF00B28141, + E81BE23D055EDACF00B28141, + E81BE31D055EDAD500B28141, + E81BE2F4055EDAD400B28141, + E81BE4BA055EDC0200B28141, + E81BE4B4055EDBCB00B28141, + E81BE4B7055EDBF100B28141, + E81BE4BD055EDC2400B28141, + E81BE243055EDACF00B28141, + E81BE29E055EDAD200B28141, + ); + isa = PBXGroup; + name = NGMime; + refType = 4; + sourceTree = ""; + }; + E81EF5D4055DC9E6006FE529 = { + children = ( + E81BE41E055EDAF900B28141, + E81BE41F055EDAF900B28141, + E81BE3FE055EDAF900B28141, + E81BE400055EDAF900B28141, + E81BE401055EDAF900B28141, + E81BE420055EDAF900B28141, + E81BE407055EDAF900B28141, + E81BE446055EDB0100B28141, + E81BE449055EDB1E00B28141, + E81BE44C055EDB2A00B28141, + ); + isa = PBXGroup; + name = NGLdap; + refType = 4; + sourceTree = ""; + }; + E81EF5D5055DC9E9006FE529 = { + children = ( + E81E04E7055DE7E3006FE529, + E81E04B2055DE7E2006FE529, + E81E04B9055DE7E2006FE529, + E81E04BA055DE7E2006FE529, + E81E04E9055DE7E3006FE529, + E81E052A055DE833006FE529, + E81E0524055DE7F2006FE529, + E81E05C9055DE8B2006FE529, + E81E05CB055DE8B2006FE529, + E81E0527055DE816006FE529, + E81E06C3055E6EC6006FE529, + E81E06C0055E6E71006FE529, + ); + isa = PBXGroup; + name = NGStreams; + refType = 4; + sourceTree = ""; + }; + E81EF5D6055DC9F0006FE529 = { + children = ( + E81EF6A3055DD414006FE529, + E81EF6A5055DD414006FE529, + E81EF6A6055DD414006FE529, + E81EF7D7055DD41B006FE529, + E81EF7D8055DD41B006FE529, + E81EF92E055DD4DF006FE529, + E81EF925055DD4A7006FE529, + E81EF769055DD418006FE529, + E81EF922055DD49C006FE529, + E81EF6A7055DD414006FE529, + E81EF6EA055DD416006FE529, + E81EF7D9055DD41B006FE529, + E81EF7B2055DD41A006FE529, + ); + isa = PBXGroup; + name = NGExtensions; + refType = 4; + sourceTree = ""; + }; + E81EF5D7055DC9F3006FE529 = { + children = ( + E81EF610055DCA42006FE529, + E81EF5DC055DCA42006FE529, + E81EF5DE055DCA42006FE529, + E81EF5DF055DCA42006FE529, + E81EF613055DCA42006FE529, + E81EF612055DCA42006FE529, + E81EF621055DCABB006FE529, + E81EF622055DCAC2006FE529, + E81EF616055DCA4B006FE529, + E81EF617055DCA52006FE529, + ); + isa = PBXGroup; + name = EOControl; + refType = 4; + sourceTree = ""; + }; + E81EF5DC055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = ChangeLog; + path = EOControl/ChangeLog; + refType = 4; + sourceTree = ""; + }; + E81EF5DD055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = EOControl/common.h; + refType = 4; + sourceTree = ""; + }; + E81EF5DE055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = EOControl/COPYING; + refType = 4; + sourceTree = ""; + }; + E81EF5DF055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = EOControl/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81EF5E0055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOAndQualifier.m; + path = EOControl/EOAndQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF5E1055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOArrayDataSource.h; + path = EOControl/EOArrayDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF5E2055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOArrayDataSource.m; + path = EOControl/EOArrayDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF5E3055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOClassDescription.h; + path = EOControl/EOClassDescription.h; + refType = 4; + sourceTree = ""; + }; + E81EF5E4055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOClassDescription.m; + path = EOControl/EOClassDescription.m; + refType = 4; + sourceTree = ""; + }; + E81EF5E5055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOControl.h; + path = EOControl/EOControl.h; + refType = 4; + sourceTree = ""; + }; + E81EF5E6055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOControlDecls.h; + path = EOControl/EOControlDecls.h; + refType = 4; + sourceTree = ""; + }; + E81EF5E7055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EODataSource.h; + path = EOControl/EODataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF5E8055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EODataSource.m; + path = EOControl/EODataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF5E9055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EODetailDataSource.h; + path = EOControl/EODetailDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF5EA055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EODetailDataSource.m; + path = EOControl/EODetailDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF5EF055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOFetchSpecification.h; + path = EOControl/EOFetchSpecification.h; + refType = 4; + sourceTree = ""; + }; + E81EF5F0055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOFetchSpecification.m; + path = EOControl/EOFetchSpecification.m; + refType = 4; + sourceTree = ""; + }; + E81EF5F1055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOGenericRecord.h; + path = EOControl/EOGenericRecord.h; + refType = 4; + sourceTree = ""; + }; + E81EF5F2055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOGenericRecord.m; + path = EOControl/EOGenericRecord.m; + refType = 4; + sourceTree = ""; + }; + E81EF5F3055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOGlobalID.h; + path = EOControl/EOGlobalID.h; + refType = 4; + sourceTree = ""; + }; + E81EF5F4055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOGlobalID.m; + path = EOControl/EOGlobalID.m; + refType = 4; + sourceTree = ""; + }; + E81EF5F5055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOKeyComparisonQualifier.m; + path = EOControl/EOKeyComparisonQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF5F6055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOKeyGlobalID.h; + path = EOControl/EOKeyGlobalID.h; + refType = 4; + sourceTree = ""; + }; + E81EF5F7055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOKeyGlobalID.m; + path = EOControl/EOKeyGlobalID.m; + refType = 4; + sourceTree = ""; + }; + E81EF5F8055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOKeyValueArchiver.h; + path = EOControl/EOKeyValueArchiver.h; + refType = 4; + sourceTree = ""; + }; + E81EF5F9055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOKeyValueArchiver.m; + path = EOControl/EOKeyValueArchiver.m; + refType = 4; + sourceTree = ""; + }; + E81EF5FA055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOKeyValueCoding.h; + path = EOControl/EOKeyValueCoding.h; + refType = 4; + sourceTree = ""; + }; + E81EF5FB055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOKeyValueCoding.m; + path = EOControl/EOKeyValueCoding.m; + refType = 4; + sourceTree = ""; + }; + E81EF5FC055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOKeyValueQualifier.m; + path = EOControl/EOKeyValueQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF5FD055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EONotQualifier.m; + path = EOControl/EONotQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF5FE055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EONull.h; + path = EOControl/EONull.h; + refType = 4; + sourceTree = ""; + }; + E81EF5FF055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EONull.m; + path = EOControl/EONull.m; + refType = 4; + sourceTree = ""; + }; + E81EF600055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOObserver.h; + path = EOControl/EOObserver.h; + refType = 4; + sourceTree = ""; + }; + E81EF601055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOObserver.m; + path = EOControl/EOObserver.m; + refType = 4; + sourceTree = ""; + }; + E81EF602055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOOrQualifier.m; + path = EOControl/EOOrQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF603055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOQualifier.h; + path = EOControl/EOQualifier.h; + refType = 4; + sourceTree = ""; + }; + E81EF604055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOQualifier.m; + path = EOControl/EOQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF605055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOQualifierParser.m; + path = EOControl/EOQualifierParser.m; + refType = 4; + sourceTree = ""; + }; + E81EF606055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOSortOrdering.h; + path = EOControl/EOSortOrdering.h; + refType = 4; + sourceTree = ""; + }; + E81EF607055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOSortOrdering.m; + path = EOControl/EOSortOrdering.m; + refType = 4; + sourceTree = ""; + }; + E81EF608055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOSQLParser.h; + path = EOControl/EOSQLParser.h; + refType = 4; + sourceTree = ""; + }; + E81EF609055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOSQLParser.m; + path = EOControl/EOSQLParser.m; + refType = 4; + sourceTree = ""; + }; + E81EF60A055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOValidation.m; + path = EOControl/EOValidation.m; + refType = 4; + sourceTree = ""; + }; + E81EF60B055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = EOControl/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF60C055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = EOControl/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E81EF60D055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = libEOControl.def; + path = EOControl/libEOControl.def; + refType = 4; + sourceTree = ""; + }; + E81EF60E055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSArray+EOQualifier.m"; + path = "EOControl/NSArray+EOQualifier.m"; + refType = 4; + sourceTree = ""; + }; + E81EF60F055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSObject+EOQualifierOps.m"; + path = "EOControl/NSObject+EOQualifierOps.m"; + refType = 4; + sourceTree = ""; + }; + E81EF610055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = EOControl/README; + refType = 4; + sourceTree = ""; + }; + E81EF611055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = "SxCore-EOControl.graffle"; + path = "EOControl/SxCore-EOControl.graffle"; + refType = 4; + sourceTree = ""; + }; + E81EF612055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = TODO; + path = EOControl/TODO; + refType = 4; + sourceTree = ""; + }; + E81EF613055DCA42006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = EOControl/Version; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E81EF61A055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = common.make; + refType = 4; + sourceTree = ""; + }; + E81EF61B055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = COPYING; + refType = 4; + sourceTree = ""; + }; + E81EF61C055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + E81EF61D055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF61E055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = PROJECTLEAD; + refType = 4; + sourceTree = ""; + }; + E81EF61F055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + E81EF620055DCA6C006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = Version; + refType = 4; + sourceTree = ""; + }; + E81EF621055DCABB006FE529 = { + children = ( + E81EF60B055DCA42006FE529, + E81EF60C055DCA42006FE529, + E81EF60D055DCA42006FE529, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + E81EF622055DCAC2006FE529 = { + children = ( + E81EF611055DCA42006FE529, + ); + isa = PBXGroup; + name = Documentation; + refType = 4; + sourceTree = ""; + }; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + EOControl + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.EOControl + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = ""; + }; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGExtensions + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGExtensions + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGStreams + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGStreams + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGMime + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGMime + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGiCal + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGiCal + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = ""; + }; + E81EF6A4055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = NGExtensions/common.h; + refType = 4; + sourceTree = ""; + }; + E81EF6A5055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = NGExtensions/COPYING; + refType = 4; + sourceTree = ""; + }; + E81EF6A6055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYRIGHT; + path = NGExtensions/COPYRIGHT; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81EF6A8055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81EF6A9055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOCacheDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF6AA055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOCompoundDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF6AB055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EODataSource+NGExtensions.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6AC055DD414006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOFilterDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF6AD055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOGrouping.m; + refType = 4; + sourceTree = ""; + }; + E81EF6AE055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOGroupingSet.m; + refType = 4; + sourceTree = ""; + }; + E81EF6AF055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOKeyGrouping.m; + refType = 4; + sourceTree = ""; + }; + E81EF6B0055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOKeyMapDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF6B1055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EOQualifier+CtxEval.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6B2055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOQualifierGrouping.m; + refType = 4; + sourceTree = ""; + }; + E81EF6B3055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = EOTrueQualifier.m; + refType = 4; + sourceTree = ""; + }; + E81EF6B4055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF6B5055DD415006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSArray+EOGrouping.m"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81EF6EB055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81EF6EC055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF6ED055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGPropertyListParser.m; + refType = 4; + sourceTree = ""; + }; + E81EF6EE055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSArray+enumerator.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6EF055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSAutoreleasePool+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F0055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSCalendarDate+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F1055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSData+gzip.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F2055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSData+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F3055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSDictionary+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F4055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSEnumerator+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F5055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSException+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F6055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSFileManager+Extensions.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F7055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSMethodSignature+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F8055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSNull+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6F9055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSObject+Logs.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FA055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSObject+Values.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FB055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSProcessInfo+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FC055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSRunLoop+FileObjects.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FD055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSSet+enumerator.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FE055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+Encoding.m"; + refType = 4; + sourceTree = ""; + }; + E81EF6FF055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+Ext.m"; + refType = 4; + sourceTree = ""; + }; + E81EF700055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+Formatting.m"; + refType = 4; + sourceTree = ""; + }; + E81EF701055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF702055DD416006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSURL+misc.m"; + refType = 4; + sourceTree = ""; + }; + E81EF75F055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = FileObjectHolder.m; + path = NGExtensions/FileObjectHolder.m; + refType = 4; + sourceTree = ""; + }; + E81EF760055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = NGExtensions/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF761055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = NGExtensions/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E81EF762055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = libNGExtensions.def; + path = NGExtensions/libNGExtensions.def; + refType = 4; + sourceTree = ""; + }; + E81EF763055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGBase64Coding.m; + path = NGExtensions/NGBase64Coding.m; + refType = 4; + sourceTree = ""; + }; + E81EF764055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGBitSet.m; + path = NGExtensions/NGBitSet.m; + refType = 4; + sourceTree = ""; + }; + E81EF765055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGBundleManager.m; + path = NGExtensions/NGBundleManager.m; + refType = 4; + sourceTree = ""; + }; + E81EF767055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGCustomFileManager.m; + path = NGExtensions/NGCustomFileManager.m; + refType = 4; + sourceTree = ""; + }; + E81EF768055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGDirectoryEnumerator.m; + path = NGExtensions/NGDirectoryEnumerator.m; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81EF76A055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = AutoDefines.h; + refType = 4; + sourceTree = ""; + }; + E81EF76B055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "DOMNode+EOQualifier.h"; + refType = 4; + sourceTree = ""; + }; + E81EF76C055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOCacheDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF76D055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOCompoundDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF76E055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "EODataSource+NGExtensions.h"; + refType = 4; + sourceTree = ""; + }; + E81EF76F055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOFilterDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF770055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOGrouping.h; + refType = 4; + sourceTree = ""; + }; + E81EF771055DD418006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOGroupingSet.h; + refType = 4; + sourceTree = ""; + }; + E81EF772055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOKeyGrouping.h; + refType = 4; + sourceTree = ""; + }; + E81EF773055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOKeyMapDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF774055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "EOQualifier+CtxEval.h"; + refType = 4; + sourceTree = ""; + }; + E81EF775055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOQualifierGrouping.h; + refType = 4; + sourceTree = ""; + }; + E81EF776055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = EOTrueQualifier.h; + refType = 4; + sourceTree = ""; + }; + E81EF777055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = FileObjectHolder.h; + refType = 4; + sourceTree = ""; + }; + E81EF778055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = IndexFunc.h; + refType = 4; + sourceTree = ""; + }; + E81EF779055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBase64Coding.h; + refType = 4; + sourceTree = ""; + }; + E81EF77A055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBaseTypes.h; + refType = 4; + sourceTree = ""; + }; + E81EF77B055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBitSet.h; + refType = 4; + sourceTree = ""; + }; + E81EF77C055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGBundleManager.h; + refType = 4; + sourceTree = ""; + }; + E81EF77D055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGCharBuffers.h; + refType = 4; + sourceTree = ""; + }; + E81EF77F055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGCustomFileManager.h; + refType = 4; + sourceTree = ""; + }; + E81EF780055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGDirectoryEnumerator.h; + refType = 4; + sourceTree = ""; + }; + E81EF781055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGExtensions.h; + refType = 4; + sourceTree = ""; + }; + E81EF782055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGExtensionsDecls.h; + refType = 4; + sourceTree = ""; + }; + E81EF783055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFileFolderInfoDataSource.h; + refType = 4; + sourceTree = ""; + }; + E81EF784055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFileManager.h; + refType = 4; + sourceTree = ""; + }; + E81EF785055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGFileManagerURL.h; + refType = 4; + sourceTree = ""; + }; + E81EF786055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGHashMap.h; + refType = 4; + sourceTree = ""; + }; + E81EF787055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMemoryAllocation.h; + refType = 4; + sourceTree = ""; + }; + E81EF788055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGMerging.h; + refType = 4; + sourceTree = ""; + }; + E81EF789055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGObjCRuntime.h; + refType = 4; + sourceTree = ""; + }; + E81EF78A055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGObjectMacros.h; + refType = 4; + sourceTree = ""; + }; + E81EF78B055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGPropertyListParser.h; + refType = 4; + sourceTree = ""; + }; + E81EF78C055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGQuotedPrintableCoding.h; + refType = 4; + sourceTree = ""; + }; + E81EF78D055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRule.h; + refType = 4; + sourceTree = ""; + }; + E81EF78E055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRuleAssignment.h; + refType = 4; + sourceTree = ""; + }; + E81EF78F055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRuleContext.h; + refType = 4; + sourceTree = ""; + }; + E81EF790055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRuleEngine.h; + refType = 4; + sourceTree = ""; + }; + E81EF791055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRuleModel.h; + refType = 4; + sourceTree = ""; + }; + E81EF792055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStack.h; + refType = 4; + sourceTree = ""; + }; + E81EF793055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGStringScanEnumerator.h; + refType = 4; + sourceTree = ""; + }; + E81EF794055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSArray+enumerator.h"; + refType = 4; + sourceTree = ""; + }; + E81EF795055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSAutoreleasePool+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF796055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSCalendarDate+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF797055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSData+gzip.h"; + refType = 4; + sourceTree = ""; + }; + E81EF798055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSData+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF799055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSDictionary+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79A055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSEnumerator+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79B055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSException+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79C055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSFileManager+Extensions.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79D055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSMethodSignature+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79E055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSNull+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF79F055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSObject+Logs.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A0055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSObject+Values.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A1055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSProcessInfo+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A2055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSRunLoop+FileObjects.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A3055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSSet+enumerator.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A4055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+Encoding.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A5055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+Ext.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A6055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+Formatting.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A7055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSString+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A8055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "NSURL+misc.h"; + refType = 4; + sourceTree = ""; + }; + E81EF7A9055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGExtensions.m; + path = NGExtensions/NGExtensions.m; + refType = 4; + sourceTree = ""; + }; + E81EF7AA055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFileFolderInfoDataSource.m; + path = NGExtensions/NGFileFolderInfoDataSource.m; + refType = 4; + sourceTree = ""; + }; + E81EF7AB055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFileManager.m; + path = NGExtensions/NGFileManager.m; + refType = 4; + sourceTree = ""; + }; + E81EF7AC055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NGFileManager+JS.m"; + path = "NGExtensions/NGFileManager+JS.m"; + refType = 4; + sourceTree = ""; + }; + E81EF7AD055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGFileManagerURL.m; + path = NGExtensions/NGFileManagerURL.m; + refType = 4; + sourceTree = ""; + }; + E81EF7AE055DD419006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGHashMap.m; + path = NGExtensions/NGHashMap.m; + refType = 4; + sourceTree = ""; + }; + E81EF7AF055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMerging.m; + path = NGExtensions/NGMerging.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B0055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGObjCRuntime.m; + path = NGExtensions/NGObjCRuntime.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B1055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGQuotedPrintableCoding.m; + path = NGExtensions/NGQuotedPrintableCoding.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B2055DD41A006FE529 = { + children = ( + E81EF7B3055DD41A006FE529, + E81EF7C7055DD41A006FE529, + E81EF7B4055DD41A006FE529, + E81EF7B5055DD41A006FE529, + E81EF7B6055DD41A006FE529, + E81EF7B7055DD41A006FE529, + E81EF7B8055DD41A006FE529, + E81EF7B9055DD41A006FE529, + E81EF7BA055DD41A006FE529, + ); + isa = PBXGroup; + name = NGRuleEngine; + path = NGExtensions/NGRuleEngine.subproj; + refType = 4; + sourceTree = ""; + }; + E81EF7B3055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81EF7B4055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E81EF7B5055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGRule.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B6055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGRuleAssignment.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B7055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGRuleContext.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B8055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGRuleModel.m; + refType = 4; + sourceTree = ""; + }; + E81EF7B9055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGRuleParser.h; + refType = 4; + sourceTree = ""; + }; + E81EF7BA055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGRuleParser.m; + refType = 4; + sourceTree = ""; + }; + E81EF7C7055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = README; + refType = 4; + sourceTree = ""; + }; + E81EF7D4055DD41A006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStack.m; + path = NGExtensions/NGStack.m; + refType = 4; + sourceTree = ""; + }; + E81EF7D5055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGStringScanEnumerator.m; + path = NGExtensions/NGStringScanEnumerator.m; + refType = 4; + sourceTree = ""; + }; + E81EF7D6055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text.xml; + name = "SxCore-NGExtensions.graffle"; + path = "NGExtensions/SxCore-NGExtensions.graffle"; + refType = 4; + sourceTree = ""; + }; + E81EF7D7055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = TODO; + path = NGExtensions/TODO; + refType = 4; + sourceTree = ""; + }; + E81EF7D8055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = Version; + path = NGExtensions/Version; + refType = 4; + sourceTree = ""; + }; + E81EF7D9055DD41B006FE529 = { + children = ( + E81EF7DA055DD41B006FE529, + E81EF7DC055DD41B006FE529, + E81EF7DB055DD41B006FE529, + ); + isa = PBXGroup; + name = "XML Extensions"; + path = NGExtensions/XmlExt.subproj; + refType = 4; + sourceTree = ""; + }; + E81EF7DA055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = .cvsignore; + refType = 4; + sourceTree = ""; + }; + E81EF7DB055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "DOMNode+EOQualifier.m"; + refType = 4; + sourceTree = ""; + }; + E81EF7DC055DD41B006FE529 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + path = GNUmakefile; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E81EF925055DD4A7006FE529 = { + children = ( + E81EF760055DD418006FE529, + E81EF761055DD418006FE529, + E81EF762055DD418006FE529, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + E81EF92E055DD4DF006FE529 = { + children = ( + E81EF7D6055DD41B006FE529, + ); + isa = PBXGroup; + name = Documentation; + refType = 4; + sourceTree = ""; + }; + E81EFB2F055DD862006FE529 = { + children = ( + E81EF61A055DCA6C006FE529, + E81EF61D055DCA6C006FE529, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + E820934105B0D30B0088B931 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imCommon.h; + refType = 4; + sourceTree = ""; + }; + E820934205B0D30B0088B931 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = imTimeMacros.h; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E820934605B0D4B00088B931 = { + children = ( + E8F255DD05769D0B0049F554, + E8F255E105769D0B0049F554, + E8F255E205769D0B0049F554, + E8F255E305769D0B0049F554, + E8F255E405769D0B0049F554, + E8F255E505769D0B0049F554, + E8F255E605769D0B0049F554, + E8F255E705769D0B0049F554, + E8F255EA05769D0B0049F554, + E8F255FC05769D0B0049F554, + E8F2560005769D0B0049F554, + E8F2560105769D0B0049F554, + E8F2560205769D0B0049F554, + E8F255FF05769D0B0049F554, + ); + isa = PBXGroup; + name = "Core Stuff"; + refType = 4; + sourceTree = ""; + }; + E820934705B0D4BD0088B931 = { + children = ( + E8F255F605769D0B0049F554, + E8F255F705769D0B0049F554, + E8F255F805769D0B0049F554, + E8F255FD05769D0B0049F554, + ); + isa = PBXGroup; + name = LDAP; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E824CFE805BD7C9C0081A110 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4FolderGlobalID.m; + refType = 4; + sourceTree = ""; + }; + E824CFE905BD7C9C0081A110 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4MessageGlobalID.h; + refType = 4; + sourceTree = ""; + }; + E824CFEA05BD7C9C0081A110 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4MessageGlobalID.m; + refType = 4; + sourceTree = ""; + }; + E824CFEB05BD7C9C0081A110 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4ServerGlobalID.h; + refType = 4; + sourceTree = ""; + }; + E824CFEC05BD7C9C0081A110 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4ServerGlobalID.m; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E84E826305C14F81005792AF = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4FolderFlags.m; + refType = 4; + sourceTree = ""; + }; + E84E826405C14F81005792AF = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4FolderMailRegistry.h; + refType = 4; + sourceTree = ""; + }; + E84E826505C14F81005792AF = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4FolderMailRegistry.m; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + E897B35B05B84D5B00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeContentLengthHeaderFieldParser.m; + path = NGMime/NGMimeContentLengthHeaderFieldParser.m; + refType = 4; + sourceTree = ""; + }; + E897B35C05B84D5B00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeContentTypeHeaderFieldParser.m; + path = NGMime/NGMimeContentTypeHeaderFieldParser.m; + refType = 4; + sourceTree = ""; + }; + E897B35D05B84D5B00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeRFC822DateHeaderFieldParser.m; + path = NGMime/NGMimeRFC822DateHeaderFieldParser.m; + refType = 4; + sourceTree = ""; + }; + E897B35E05B84D5B00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = NGMimeStringHeaderFieldParser.m; + path = NGMime/NGMimeStringHeaderFieldParser.m; + refType = 4; + sourceTree = ""; + }; + E897B35F05B84D5B00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "NSCalendarDate+RFC822.m"; + path = "NGMime/NSCalendarDate+RFC822.m"; + refType = 4; + sourceTree = ""; + }; + E897B36605B84D6000B708BC = { + children = ( + E897B38C05B8523E00B708BC, + E897B35A05B84D5B00B708BC, + E897B35B05B84D5B00B708BC, + E897B35C05B84D5B00B708BC, + E897B35D05B84D5B00B708BC, + E897B35E05B84D5B00B708BC, + E897B35F05B84D5B00B708BC, + ); + isa = PBXGroup; + name = "Headerfield Parsers"; + refType = 4; + sourceTree = ""; + }; + E897B36705B84D7800B708BC = { + children = ( + E81BE2F8055EDAD400B28141, + E81BE306055EDAD400B28141, + E81BE311055EDAD500B28141, + E80D72C805D6BAB10050931F, + E80D72C905D6BAB10050931F, + E80D72CA05D6BAB10050931F, + E80D72CB05D6BAB10050931F, + E80D72CC05D6BAB10050931F, + E80D72CD05D6BAB10050931F, + E80D72CE05D6BAB10050931F, + ); + isa = PBXGroup; + name = Generators; + refType = 4; + sourceTree = ""; + }; + E897B36805B84DAA00B708BC = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EOQualifier+IMAPAdditions.m"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E897B38D05B8523E00B708BC = { + fileRef = E897B38C05B8523E00B708BC; + isa = PBXBuildFile; + settings = { + }; + }; + E8ACC6BE05CED366005ADB68 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = NGImap4ResponseNormalizer.h; + refType = 4; + sourceTree = ""; + }; + E8ACC6BF05CED366005ADB68 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = NGImap4ResponseNormalizer.m; + refType = 4; + sourceTree = ""; + }; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGImap4 + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGImap4 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGMail + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGMail + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = ""; + }; + E8CA84890605CB64006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EOFetchSpecification+plist.m"; + refType = 4; + sourceTree = ""; + }; + E8CA848A0605CB64006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EOQualifier+plist.m"; + refType = 4; + sourceTree = ""; + }; + E8CA848B0605CB64006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "EOSortOrdering+plist.m"; + refType = 4; + sourceTree = ""; + }; + E8CA84950605CB6D006366AB = { + children = ( + E81EF6A8055DD414006FE529, + E81EF6B4055DD415006FE529, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + E8CA84BB0605CB7E006366AB = { + children = ( + E8CA84E30605CBD5006366AB, + E8CA84E40605CBD5006366AB, + E8CA84E50605CBD5006366AB, + E81EF76C055DD418006FE529, + E81EF76D055DD418006FE529, + E81EF76E055DD418006FE529, + E81EF76F055DD418006FE529, + E81EF770055DD418006FE529, + E81EF771055DD418006FE529, + E81EF772055DD419006FE529, + E81EF773055DD419006FE529, + E81EF774055DD419006FE529, + E81EF775055DD419006FE529, + E81EF776055DD419006FE529, + ); + isa = PBXGroup; + name = "EOControl Extensions"; + refType = 4; + sourceTree = ""; + }; + E8CA84C40605CB89006366AB = { + children = ( + E81EF76B055DD418006FE529, + ); + isa = PBXGroup; + name = "XML Extensions"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E8CA84DC0605CBAD006366AB = { + children = ( + E81EF78D055DD419006FE529, + E81EF78E055DD419006FE529, + E81EF78F055DD419006FE529, + E81EF790055DD419006FE529, + E81EF791055DD419006FE529, + ); + isa = PBXGroup; + name = "Rule Engine"; + refType = 4; + sourceTree = ""; + }; + E8CA84E30605CBD5006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "EOFetchSpecification+plist.h"; + refType = 4; + sourceTree = ""; + }; + E8CA84E40605CBD5006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "EOQualifier+plist.h"; + refType = 4; + sourceTree = ""; + }; + E8CA84E50605CBD5006366AB = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = "EOSortOrdering+plist.h"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E8F255DD05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = bmlookup.m; + path = samples/bmlookup.m; + refType = 4; + sourceTree = ""; + }; + E8F255DE05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = ChangeLog; + path = samples/ChangeLog; + refType = 4; + sourceTree = ""; + }; + E8F255DF05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = common.h; + path = samples/common.h; + refType = 4; + sourceTree = ""; + }; + E8F255E005769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = COPYING; + path = samples/COPYING; + refType = 4; + sourceTree = ""; + }; + E8F255E105769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = encoding.m; + path = samples/encoding.m; + refType = 4; + sourceTree = ""; + }; + E8F255E205769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EncodingTool.h; + path = samples/EncodingTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255E305769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EncodingTool.m; + path = samples/EncodingTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255E405769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = eoqual.m; + path = samples/eoqual.m; + refType = 4; + sourceTree = ""; + }; + E8F255E505769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = EOQualTool.h; + path = samples/EOQualTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255E605769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = EOQualTool.m; + path = samples/EOQualTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255E705769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = fmdls.m; + path = samples/fmdls.m; + refType = 4; + sourceTree = ""; + }; + E8F255E805769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile; + path = samples/GNUmakefile; + refType = 4; + sourceTree = ""; + }; + E8F255E905769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = GNUmakefile.preamble; + path = samples/GNUmakefile.preamble; + refType = 4; + sourceTree = ""; + }; + E8F255EA05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = httpu_notify.m; + path = samples/httpu_notify.m; + refType = 4; + sourceTree = ""; + }; + E8F255EB05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ical2.m; + path = samples/ical2.m; + refType = 4; + sourceTree = ""; + }; + E8F255EC05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ical3.m; + path = samples/ical3.m; + refType = 4; + sourceTree = ""; + }; + E8F255ED05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = imap_tool.m; + path = samples/imap_tool.m; + refType = 4; + sourceTree = ""; + }; + E8F255EE05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ImapListTool.h; + path = samples/ImapListTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255EF05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ImapListTool.m; + path = samples/ImapListTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255F005769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = imapls.m; + path = samples/imapls.m; + refType = 4; + sourceTree = ""; + }; + E8F255F105769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = imapquota.m; + path = samples/imapquota.m; + refType = 4; + sourceTree = ""; + }; + E8F255F205769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ImapQuotaTool.h; + path = samples/ImapQuotaTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255F305769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ImapQuotaTool.m; + path = samples/ImapQuotaTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255F405769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = ImapTool.h; + path = samples/ImapTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255F505769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ImapTool.m; + path = samples/ImapTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255F605769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ldap2dsml.m; + path = samples/ldap2dsml.m; + refType = 4; + sourceTree = ""; + }; + E8F255F705769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ldapchkpwd.m; + path = samples/ldapchkpwd.m; + refType = 4; + sourceTree = ""; + }; + E8F255F805769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = ldapls.m; + path = samples/ldapls.m; + refType = 4; + sourceTree = ""; + }; + E8F255F905769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = mime2xml.m; + path = samples/mime2xml.m; + refType = 4; + sourceTree = ""; + }; + E8F255FA05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = Mime2XmlTool.h; + path = samples/Mime2XmlTool.h; + refType = 4; + sourceTree = ""; + }; + E8F255FB05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = Mime2XmlTool.m; + path = samples/Mime2XmlTool.m; + refType = 4; + sourceTree = ""; + }; + E8F255FC05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = parserule.m; + path = samples/parserule.m; + refType = 4; + sourceTree = ""; + }; + E8F255FD05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "pwd-check.m"; + path = "samples/pwd-check.m"; + refType = 4; + sourceTree = ""; + }; + E8F255FE05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = text; + name = README; + path = samples/README; + refType = 4; + sourceTree = ""; + }; + E8F255FF05769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = subclassing.m; + path = samples/subclassing.m; + refType = 4; + sourceTree = ""; + }; + E8F2560005769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = test_qpdecode.m; + path = samples/test_qpdecode.m; + refType = 4; + sourceTree = ""; + }; + E8F2560105769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = testdirenum.m; + path = samples/testdirenum.m; + refType = 4; + sourceTree = ""; + }; + E8F2560205769D0B0049F554 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = testsock.m; + path = samples/testsock.m; + refType = 4; + sourceTree = ""; + }; + E8F2560505769D2F0049F554 = { + children = ( + E8F255E805769D0B0049F554, + E8F255E905769D0B0049F554, + ); + isa = PBXGroup; + name = Makefiles; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E8FDB0CB056C297A002DFB9D = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+URLEscaping.m"; + refType = 4; + sourceTree = ""; + }; + E8FDB0CC056C297A002DFB9D = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "NSString+XMLEscaping.m"; + refType = 4; + sourceTree = ""; + }; + 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 = ""; + }; + E8FDB0E9056C3DE4002DFB9D = { + fileRef = E81BE450055EDB5600B28141; + isa = PBXBuildFile; + settings = { + }; + }; + }; + rootObject = E81EF5C7055DC9BE006FE529; +} diff --git a/skyrix-core/Version b/skyrix-core/Version new file mode 100644 index 00000000..2dfd0b9c --- /dev/null +++ b/skyrix-core/Version @@ -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 index 00000000..c01b9110 --- /dev/null +++ b/skyrix-core/common.make @@ -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 index 00000000..1f05c8b2 --- /dev/null +++ b/skyrix-core/dummy.c @@ -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 index 00000000..f6f5660a --- /dev/null +++ b/skyrix-core/samples/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-core/samples/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..f78f6b57 --- /dev/null +++ b/skyrix-core/samples/ChangeLog @@ -0,0 +1,129 @@ +2004-08-17 Helge Hess + + * subclassing.m: fixed a compiler warning + +2004-07-09 Helge Hess + + * bmlookup.m: major code cleanups, improved output + +2004-06-27 Helge Hess + + * ldap2dsml.m: fixed a compile warning + +2004-06-21 Helge Hess + + * common.h: fixed compatibility with gstep-base + +2004-06-17 Helge Hess + + * added 'testurl' to test NSURL for the Cocoa Foundation bug wrt the + trailing suffix in -path + +2004-05-09 Helge Hess + + * subclassing.m: added support for Apple runtime + +2004-04-12 Helge Hess + + * ImapListTool, ImapTool.m, imapls.m: minor code cleanups + +2004-01-19 Helge Hess + + * ldapls.m: minor fixes (moved NSAutoreleasePool to correct place) + +2004-01-11 Helge Hess + + * minor cleanups to log messages + +2003-10-12 Helge Hess + + * 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 + + * added parserule for testing parsing of NGRule objects + +2003-05-14 Helge Hess + + * some gcc 3.3 warnings fixed + +2003-04-03 Helge Hess + + * GNUmakefile: added ldapchkpwd tool + + * ldap2dsml.m: added autorelease-pool to main() + +2003-04-01 GNUstep User + + * ImapListTool.m: do not use NSFileIdentifier constant + + * EncodingTool.m: removed some undeclared encodings when compiling for + GNUstep Base + +2003-02-12 Helge Hess + + * added ical2.m, ical3.m - examples for NGiCal + +2003-01-30 Helge Hess + + * added httpu_notify, a small tool to send out HTTP-over-UDP + NOTIFY notifications + +2003-01-08 Helge Hess + + * testsock.m: improved test code + +2003-01-07 Helge Hess + + * 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 + + * Mime2XmlTool.m: fixed a protocol warning + +Mon Dec 23 15:36:01 2002 Helge Hess + + * ImapListTool.m: pass correct filemanager as a parameter + +2002-12-08 Helge Hess + + * testdirenum.m: cleanups + +Tue Dec 17 15:07:40 2002 + + * imapquota.m: add quota test + +2002-11-21 Jan Reichmann + + * added Imap-Super class, improve imapls + +2002-11-21 Helge Hess + + * added ldapls, ldap2dsml as examples for NGLdap + +2002-11-15 Helge Hess + + * EOQualTool.m: added test for complex cast + +2002-10-29 Helge Hess + + * EOQualTool.m: added support for parsing SQL using the new EOSQLParser + +2002-10-25 Helge Hess + + * 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 index 00000000..e8dedb47 --- /dev/null +++ b/skyrix-core/samples/EOQualTool.h @@ -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 + +@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 index 00000000..3d56f2bf --- /dev/null +++ b/skyrix-core/samples/EOQualTool.m @@ -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 +#include + +@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 \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 index 00000000..a658f7d5 --- /dev/null +++ b/skyrix-core/samples/EncodingTool.h @@ -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 +#import + +@class NSString; + +/* + Supported Args: + -from_encoding (Default: defaultCStringEncoding) + -to_encoding (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 index 00000000..f9e17d9b --- /dev/null +++ b/skyrix-core/samples/EncodingTool.m @@ -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 +#import +#import + +@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 \n"); + fprintf(stderr, " -from_encoding \n"); + fprintf(stderr, " -to_encoding \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 index 00000000..d0af1267 --- /dev/null +++ b/skyrix-core/samples/GNUmakefile @@ -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 index 00000000..7bf84719 --- /dev/null +++ b/skyrix-core/samples/GNUmakefile.preamble @@ -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 index 00000000..4c37d8bb --- /dev/null +++ b/skyrix-core/samples/ImapListTool.h @@ -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 (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 index 00000000..ad2b7b6a --- /dev/null +++ b/skyrix-core/samples/ImapListTool.m @@ -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 +#include +#include +#include + +@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)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)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)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 ?part=\n"); + fprintf(stderr, "usage: imapls \n"); + fprintf(stderr, " -url \n"); + fprintf(stderr, " -user \n"); + fprintf(stderr, " -password \n"); + fprintf(stderr, " -host \n"); + fprintf(stderr, " -datasource YES|NO\n"); + fprintf(stderr, " -out ls|xml\n"); + fprintf(stderr, " -statistics YES|NO\n"); + fprintf(stderr, " -preloops \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 index 00000000..ad9025d9 --- /dev/null +++ b/skyrix-core/samples/ImapQuotaTool.h @@ -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 index 00000000..cfcf6089 --- /dev/null +++ b/skyrix-core/samples/ImapQuotaTool.m @@ -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 +#include +#include +#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 index 00000000..33b86c3c --- /dev/null +++ b/skyrix-core/samples/ImapTool.h @@ -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 + +@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 index 00000000..df974cea --- /dev/null +++ b/skyrix-core/samples/ImapTool.m @@ -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 +#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 index 00000000..30c8d11d --- /dev/null +++ b/skyrix-core/samples/Mime2XmlTool.h @@ -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 + +@class NSArray; + +/* + Supported Args: + -statistics YES|NO (print statistics, parsing time, memory) + -streams YES|NO (either use streaming IO or memory mapped data) + -preloops (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 index 00000000..87569e22 --- /dev/null +++ b/skyrix-core/samples/Mime2XmlTool.m @@ -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 +#import +#import + +@interface Mime2XmlTool(Privates) +- (BOOL)_outputPartAsXML:(id)_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 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 length]); + if ([body length] > 256) { + body = [body substringToIndex:255]; + printf("%s", [body cString]); + } + printf("\n"); + return YES; +} +- (BOOL)_outputDataBody:(NSData *)body { + [self indent]; + printf("...\n", + [body length]); + return YES; +} +- (BOOL)_outputPartBody:(id)body { + [self indent]; + printf("\n"); + [self _outputPartAsXML:(id)body]; + [self indent]; + printf("\n"); + return YES; +} +- (BOOL)_outputMultiPartBody:(id)body { + [self indent]; + printf("\n"); + + [self _outputMultipartBody:(id)body]; + + [self indent]; + printf("\n"); + return YES; +} + +- (BOOL)_outputHeaderField:(NSString *)_field value:(id)_value { + Class clazz; + NSString *s; + [self indent]; + + clazz = [_value class]; + printf(""); + + s = [_value stringValue]; + s = [s stringByEscapingXMLString]; + printf("%s", [s cString]); + + printf("\n"); + return YES; +} +- (BOOL)_outputPartHeaders:(id)_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)_part { + id tmp; + id body; + + if (_part == nil) { + NSLog(@"got no part ..."); + return NO; + } + + [self indent]; + 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("\n"); + return YES; +} + +- (BOOL)outputPartAsXML:(id)_part { + self->outIndent = 0; + printf("\n"); + return [self _outputPartAsXML:_part]; +} + +- (BOOL)outputPartAsMime:(id)_part { + return NO; +} + +- (BOOL)outputPart:(id)_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)parseFile:(NSString *)_path useStreams:(BOOL)_streams { + NSAutoreleasePool *pool; + NGMimePartParser *parser; + id 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 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 *\n"); + fprintf(stderr, " -preloops \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 index 00000000..692d2a6d --- /dev/null +++ b/skyrix-core/samples/README @@ -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 index 00000000..d3a63dd5 --- /dev/null +++ b/skyrix-core/samples/bmlookup.m @@ -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 +#include +#include +#include + +@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 index 00000000..408caa9c --- /dev/null +++ b/skyrix-core/samples/common.h @@ -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 + +#if LIB_FOUNDATION_LIBRARY +# include +#else +# include +# include +#endif + +#include diff --git a/skyrix-core/samples/encoding.m b/skyrix-core/samples/encoding.m new file mode 100644 index 00000000..1d738288 --- /dev/null +++ b/skyrix-core/samples/encoding.m @@ -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 index 00000000..922bea1c --- /dev/null +++ b/skyrix-core/samples/eoqual.m @@ -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 index 00000000..be3b4ee2 --- /dev/null +++ b/skyrix-core/samples/fmdls.m @@ -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 +#import +#include +#include +#include + +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: %@ ", [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 index 00000000..5c63a911 --- /dev/null +++ b/skyrix-core/samples/httpu_notify.m @@ -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 +#include +#include +#include +#include + +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 index 00000000..e7c66dd9 --- /dev/null +++ b/skyrix-core/samples/ical2.m @@ -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 +#include + +@interface iCal2Tool : NSObject +{ + id 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 index 00000000..deccf791 --- /dev/null +++ b/skyrix-core/samples/ical3.m @@ -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 + +@class EOQualifier, NSString, EOSortOrdering; + +@interface iCal3Tool : NSObject +{ + EOQualifier *qualifier; + NSString *entityName; + NSArray *sortOrderings; +} + +- (int)runWithArguments:(NSArray *)_args; + +@end + +#include +#include +#include +#include +#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 index 00000000..397bf3ab --- /dev/null +++ b/skyrix-core/samples/imap_tool.m @@ -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 index 00000000..5e6e6f26 --- /dev/null +++ b/skyrix-core/samples/imapls.m @@ -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 index 00000000..6c036733 --- /dev/null +++ b/skyrix-core/samples/imapquota.m @@ -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 index 00000000..7733220b --- /dev/null +++ b/skyrix-core/samples/ldap2dsml.m @@ -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 +#import +#import +#import +#import +#include "common.h" + +@interface DSMLSaxProducer : NSObject +{ + id contentHandler; + id errorHandler; +} + +- (void)setContentHandler:(id)_handler; +- (void)setErrorHandler:(id)_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)_handler { + ASSIGN(self->contentHandler, _handler); +} +- (void)setErrorHandler:(id)_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 + +@interface DSMLSaxOutputter : SaxDefaultHandler +{ + int level; +} +@end + +@implementation DSMLSaxOutputter + +- (void)startElement:(NSString *)_localName + namespace:(NSString *)_ns + rawName:(NSString *)_rawName + attributes:(id)_attrs +{ + int i, count; + + level++; + for (i = 0; i < level; i++) + printf(" "); + printf("\n"); +} + +- (void)endElement:(NSString *)_localName + namespace:(NSString *)_ns + rawName:(NSString *)_rawName +{ + int i; + for (i = 0; i < level; i++) + printf(" "); + printf("\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 + +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: %@ ", [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 index 00000000..feaaa7ca --- /dev/null +++ b/skyrix-core/samples/ldapchkpwd.m @@ -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 +#import +#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: %@ ", [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 index 00000000..9ae1ce64 --- /dev/null +++ b/skyrix-core/samples/ldapls.m @@ -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 +#include +#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: %@ ", [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 index 00000000..67c1c091 --- /dev/null +++ b/skyrix-core/samples/mime2xml.m @@ -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 index 00000000..2ebb207c --- /dev/null +++ b/skyrix-core/samples/parserule.m @@ -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 +#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 index 00000000..ea0be84f --- /dev/null +++ b/skyrix-core/samples/pwd-check.m @@ -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 + * 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 +#include +#include +#include +#include +//#include + +/* 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 +#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 index 00000000..4a5ca610 --- /dev/null +++ b/skyrix-core/samples/subclassing.m @@ -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 +#include +#include + +#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY +# include +#endif + +#if APPLE_RUNTIME +# include +# 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 index 00000000..3c8a431e --- /dev/null +++ b/skyrix-core/samples/test_qpdecode.m @@ -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 index 00000000..88cddd74 --- /dev/null +++ b/skyrix-core/samples/testdirenum.m @@ -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 +#import +#include +#include +#include + +@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 index 00000000..96cb03a1 --- /dev/null +++ b/skyrix-core/samples/testsock.m @@ -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 +#include + +@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:@"\n"]; + [txt writeString:@"\n"]; + [txt writeString:@"system.listMethods\n"]; + [txt writeString:@"\n"]; + [txt writeString:@"\n"]; + [txt writeString:@"\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 index 00000000..f5a63e36 --- /dev/null +++ b/skyrix-core/samples/testurl.m @@ -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 +#include + +@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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-sope/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..8e764497 --- /dev/null +++ b/skyrix-sope/COPYRIGHT @@ -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 index 00000000..1dcd6aaa --- /dev/null +++ b/skyrix-sope/ChangeLog @@ -0,0 +1,83 @@ +2004-07-21 Marcus Mueller + + * SOPE.xcode: fixed an incorrect framework search path. + +2004-07-21 Marcus Mueller + + * 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 + + * 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 + + * SOPE.xcode: removed WOPopUpButton.h. + +2004-05-16 Marcus Mueller + + * 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 + + * SOPE.xcode: added new WOMessage+Validation.m + +2004-04-28 Marcus Mueller + + * 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 + + * SOPE.xcode: added WEPageLink in WEExtensions, + WOHyperlink cluster in NGObjWeb. + +2004-04-02 Marcus Mueller + + * SOPE.xcode: Added WETableView group and accompanied files in + WEExtensions. + +2004-03-31 Marcus Mueller + + * SOPE.xcode: added WERedirect.m to WEExtensions, added WORedirect.[hm] + and WOExtensions.h to WOExtensions. + +2004-03-24 Marcus Mueller + + * SOPE.xcode: added WEQualifierConditional in WEExtensions. + Also, added -headerpad_max_install_names link option where + appropriate. + +2004-03-08 Helge Hess + + * SOPE.xcode: added new source files in WebDAV + + * README-OSX.txt: added some build notes + +2004-02-26 Helge Hess + + * added WOResourceURLAssociation to Xcode project + +2004-02-10 Marcus Mueller + + * 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 index 00000000..3dbef8bb --- /dev/null +++ b/skyrix-sope/GNUmakefile @@ -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 index 00000000..d4a0b7cb --- /dev/null +++ b/skyrix-sope/NGJavaScript/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-sope/NGJavaScript/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..1fe26726 --- /dev/null +++ b/skyrix-sope/NGJavaScript/ChangeLog @@ -0,0 +1,280 @@ +2004-08-17 Helge Hess + + * 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 + + * Core+JS.subproj/EODataSource+JS.m: fixed a gcc 3.4 warning (v4.2.29) + +2004-06-27 Helge Hess + + * 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 + + * NGJavaScriptObject.m: fixed some gcc 3.4 warning (v4.2.27) + +2004-06-10 Helge Hess + + * GNUmakefile.preamble: added prebinding (v4.2.26) + +2004-05-05 Marcus Mueller + + * 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 + + * Core+JS.subproj/EODataSource+JS.m: fixed not to use deprecated + EOControl API (v4.2.24) + +2003-12-20 Helge Hess + + * GNUmakefile (BUNDLE_INSTALL_DIR): use GNUSTEP_INSTALLATION_DIR + (v4.2.23) + +2003-11-30 Helge Hess + + * 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 + + * Core+JS.subproj/EODataSource+JS.m: replaces some retain macros with + methods (v4.2.21) + +2003-10-14 Helge Hess + + * NGJavaScriptObjectHandler.m, NGJavaScriptObjCClassInfo.m, + NGJavaScriptShadow.m: use proper ObjC runtime functions on + MacOSX (v4.2.20) + +2003-10-13 Helge Hess + + * EODataSource+JS.m, common.h: fixed compilation on MacOSX (v4.2.19) + +2003-09-09 Helge Hess + + * NGJavaScriptContext.m: returned a value in a void function (v4.2.18) + +2003-09-06 Helge Hess + + * fixed some warnings on MacOSX (v4.2.17) + +2003-07-28 Helge Hess + + * applied GNUstep patches provided by Filip Van Raemdonck for improved + compilation with gstep-base (v4.2.16) + +2003-06-20 Helge Hess + + * 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 + + * 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 + + * NGJavaScriptObjectMappingContext.m: added a fix for MacOSX (v4.2.12) + +Mon Dec 23 15:42:16 2002 Helge Hess + + * Core+JS.subproj: includes ../common.h instead of common.h (v4.2.11) + +2002-12-02 Helge Hess + + * moved to skyrix-sope-42 (v4.2.10) + +2002-10-04 Helge Hess + + * NGJavaScriptArray.m: improved NSArray compatibility, added + - containsObject: and -subarrayWithRange: (v4.2.9) + +2002-08-28 Helge Hess + + * moved NGJavaScriptError to separate file, fixed some gcc 3.2 warnings + +2002-08-27 Helge Hess + + * 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 + + * 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 + + * started implementation of NSCoding (v4.2.5) + + * NGJavaScriptObjectMappingContext.m: use -parentObject instead of + -_js_parentObject + +2002-08-05 Helge Hess + + * Core+JS.subproj/NSDate+JS.m: added JavaScript function to create + NSCalendarDate objects ... + +2002-06-12 Helge Hess + + * NGJavaScriptObjectHandler.m: fixed serious bug with incorrectly + defined JavaScript class flags + +Mon Jun 10 13:04:19 2002 Helge Hess + + * moved NGScripting to separate library + +2002-06-10 Helge Hess + + * heavy reworks towards a pluggable scripting system + +Mon Dec 17 15:22:59 2001 Helge Hess + + * NGFileManager+JS.m: added trash() function for moving files to + trash + +Tue Nov 27 16:42:20 2001 Bjoern Stierand + + * NGFileManager+JS.m: fixed wrong destination path in _jsfunc_mv() + +Tue Sep 25 12:55:53 2001 Helge Hess + + * added bindings for NGFileManager ... + + * NGJavaScriptArray.m: added -insertObject:atIndex: + +Fri Jul 13 17:19:18 2001 Helge Hess + + * NGJavaScriptObjCClassInfo.m: added support for JSPROP_SHARED instead + of JSPROP_NOSLOT + +Thu Jun 14 12:51:26 2001 Helge Hess + + * NSUserDefaults+JS.m: added JS docu + +Sat May 5 17:04:24 2001 Helge Hess + + * 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 + + * disable abort's in non-debug mode + +Mon Apr 30 21:31:18 2001 Helge Hess + + * NGJavaScriptObjectHandler.m, NGJavaScriptShadow.m: better exception + handling + +Fri Apr 27 14:27:11 2001 Helge Hess + + * EODataSource+JS.m: improved error handling + +Thu Apr 5 15:40:11 2001 Helge Hess + + * EODataSource+JS.m ([EODataSource -_updateFetchSpecWithEntityName:qualifier:sortOrderings:]): + added support for setting/getting hints + +Fri Mar 9 12:06:08 2001 Helge Hess + + * NSNumber+JS.m: convert NSBoolNumber to JS bools + +Mon Mar 5 19:43:18 2001 Helge Hess + + * NGJavaScriptArray: add NSMutableArray as behaviour + +Thu Feb 22 18:56:47 2001 Helge Hess + + * detect JavaScript construction calls (eg 'new Blah()') + +Mon Feb 12 18:28:10 2001 Helge Hess + + * NGJavaScriptObjectHandler.m: fixed remove-root bug + +Mon Jan 8 16:22:49 2001 Helge Hess + + * fixed compilation + +Fri Oct 13 17:16:42 2000 Helge Hess + + * use hashtable to map ObjC context wrapper + +Tue Sep 12 18:51:47 2000 Helge Hess + + * 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 index 00000000..6a53797d --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/.cvsignore @@ -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 index 00000000..bd325cc4 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/EODataSource+JS.m @@ -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 +#include +#include +#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 @""; +} + +- (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 index 00000000..ddba6a85 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.h @@ -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 + +@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 index 00000000..1b64e275 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/EOJavaScriptGrouping.m @@ -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 +#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 index 00000000..3c3f0c9c --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/EONull+JS.m @@ -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 +#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 index 00000000..9baac8dd --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile @@ -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 index 00000000..fb488909 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/GNUmakefile.preamble @@ -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 index 00000000..0cfea2b8 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NGFileManager+JS.m @@ -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 +#include +#include "NGJavaScriptContext.h" +#include "../common.h" +#include + +/* + 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)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 index 00000000..e77066bc --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSArray+JS.m @@ -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 index 00000000..9775ede2 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDate+JS.m @@ -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 + +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 index 00000000..b4d07ea3 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSDictionary+JS.m @@ -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 +#import +#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 index 00000000..b0102ed9 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSNumber+JS.m @@ -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 +#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 index 00000000..5204f974 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.h @@ -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 + +@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 index 00000000..7c4e4911 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSObject+JS.m @@ -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 +#include "NGJavaScriptContext.h" +#include "NGJavaScriptObjectMappingContext.h" +#include "../common.h" +#import + +@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:@"" + 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 index 00000000..9b3cd5d1 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.h @@ -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 + +#define id _id +#include +#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 index 00000000..54d8eef8 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSString+JS.m @@ -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 +#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 index 00000000..e6040383 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Core+JS.subproj/NSUserDefaults+JS.m @@ -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 +#import +#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 index 00000000..9f57a830 --- /dev/null +++ b/skyrix-sope/NGJavaScript/GNUmakefile @@ -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 index 00000000..c6750be5 --- /dev/null +++ b/skyrix-sope/NGJavaScript/GNUmakefile.preamble @@ -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 index 00000000..42a257ca --- /dev/null +++ b/skyrix-sope/NGJavaScript/JSObjectOps.m @@ -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 index 00000000..ed180f1b --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScript-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGJavaScript + CFBundleGetInfoString + + CFBundleIdentifier + com.skyrix.SOPE.NGJavaScript + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.2 + + diff --git a/skyrix-sope/NGJavaScript/NGJavaScript.h b/skyrix-sope/NGJavaScript/NGJavaScript.h new file mode 100644 index 00000000..a7dc5518 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScript.h @@ -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 +#include +#include +#include +#include + +#include + +#include + +#endif /* __NGJavaScript_H__ */ diff --git a/skyrix-sope/NGJavaScript/NGJavaScriptArray.m b/skyrix-sope/NGJavaScript/NGJavaScriptArray.m new file mode 100644 index 00000000..d4bed9e0 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptArray.m @@ -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 index 00000000..09a9d0d8 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptCallable.h @@ -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 + +@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 index 00000000..1a3f956b --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptCallable.m @@ -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 index 00000000..197c3a49 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptContext.h @@ -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 + +@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 index 00000000..7a017960 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptContext.m @@ -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 index 00000000..c64c16c6 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptDecls.h @@ -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 index 00000000..c56a9f47 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptError.h @@ -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 + +@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 index 00000000..17df7675 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptError.m @@ -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 index 00000000..2e0cfc6a --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptFunction.h @@ -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 + +@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 index 00000000..0700aba2 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptFunction.m @@ -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 index 00000000..3e8519e9 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptLanguage.m @@ -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 + +@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 index 00000000..e4bca0bc --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.h @@ -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 + +@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 index 00000000..53c66944 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjCClassInfo.m @@ -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 +#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 index 00000000..8a303b42 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObject.h @@ -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 +#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 + +/* 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 index 00000000..5d5c6745 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObject.m @@ -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 +#include +#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 index 00000000..bda7ab3d --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.h @@ -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 + +@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 index 00000000..49685ef3 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjectHandler.m @@ -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 +#import + +//#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], + "", /* 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 = ""; + + 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 index 00000000..68889d19 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.h @@ -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 +#import + +@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 index 00000000..3490aeae --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptObjectMappingContext.m @@ -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 +#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 : "", + (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 : "", + [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 index 00000000..ff8d88bc --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.h @@ -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 + +@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 index 00000000..5bdf9b6c --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptRuntime.m @@ -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 index 00000000..f16cb5a7 --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptShadow.h @@ -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 +#include + +/* + 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 index 00000000..1803a9ef --- /dev/null +++ b/skyrix-sope/NGJavaScript/NGJavaScriptShadow.m @@ -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 +#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:@"" 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 index 00000000..2a2ad7c9 --- /dev/null +++ b/skyrix-sope/NGJavaScript/README @@ -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 index 00000000..2a59cf27 --- /dev/null +++ b/skyrix-sope/NGJavaScript/ScriptLanguages.plist @@ -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 index 00000000..b07930e3 --- /dev/null +++ b/skyrix-sope/NGJavaScript/TODO @@ -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 index 00000000..1c8a2e74 --- /dev/null +++ b/skyrix-sope/NGJavaScript/Version @@ -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 index 00000000..3feeaab3 --- /dev/null +++ b/skyrix-sope/NGJavaScript/common.h @@ -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 +# include +# include +# include +# include +#undef id + +#import +#include + +#if NeXT_RUNTIME || APPLE_RUNTIME +# include +# include +#endif + +#if NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY || \ + COCOA_Foundation_LIBRARY +# include +# if 0 // no FoundationExt +# include +# include +# endif +#elif LIB_FOUNDATION_LIBRARY +# include +#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 index 00000000..90ae5c2d --- /dev/null +++ b/skyrix-sope/NGJavaScript/dummy.m @@ -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 index 00000000..561cc086 --- /dev/null +++ b/skyrix-sope/NGJavaScript/globals.h @@ -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 index 00000000..71b57671 --- /dev/null +++ b/skyrix-sope/NGJavaScript/globals.m @@ -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 + +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 index 00000000..76b93607 --- /dev/null +++ b/skyrix-sope/NGJavaScript/jsobjops.m @@ -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 +#import +#import + +#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), + "", /* source file */ + 0, /* line number */ + &lastValue); + NSCAssert(res == JS_TRUE, @"couldn't evaluate script .."); +} + +#include + +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 index 00000000..8718f72c --- /dev/null +++ b/skyrix-sope/NGJavaScript/testjs.m @@ -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 +#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 index 00000000..4d46bf0c --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/.cvsignore @@ -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 index 00000000..49c11493 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/Blah.h @@ -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 + +@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 index 00000000..faaffa21 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/Blah.m @@ -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 index 00000000..fe8d295b --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/Combined.h @@ -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 + +@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 index 00000000..2075f5a3 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/Combined.m @@ -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 index 00000000..30593710 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/GNUmakefile @@ -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 index 00000000..2ba33d80 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSArchivingTests.h @@ -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 index 00000000..d1f1f7b9 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSArchivingTests.m @@ -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 +#import +#import + +@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(: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 index 00000000..aec825a8 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSBridgeTests.h @@ -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 index 00000000..15889368 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSBridgeTests.m @@ -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 +#import +#import +#import + +#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 index 00000000..3a147fe5 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSTest.h @@ -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 + +@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 index 00000000..5f4ff3e2 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/JSTest.m @@ -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 +#import +#import + +@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 index 00000000..14b9b8a2 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/MyNum.h @@ -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 + +@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 index 00000000..4e20f406 --- /dev/null +++ b/skyrix-sope/NGJavaScript/tests/MyNum.m @@ -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 index 00000000..ed903c92 --- /dev/null +++ b/skyrix-sope/NGObjDOM/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-sope/NGObjDOM/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..c928419b --- /dev/null +++ b/skyrix-sope/NGObjDOM/COPYRIGHT @@ -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 index 00000000..528c773b --- /dev/null +++ b/skyrix-sope/NGObjDOM/ChangeLog @@ -0,0 +1,233 @@ +2004-07-19 Helge Hess + + * 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 + + * XUL.subproj/GNUmakefile, XHTML.subproj/GNUmakefile: added support + for building with GNUSTEP_BUILD_DIR env (v4.2.23) + +2004-06-10 Helge Hess + + * v4.2.22 + + * GNUmakefile.preamble: added prebinding + + * ODResourceManager.m: minor cleanups + +2004-06-09 Helge Hess + + * v4.2.21 + + * GNUmakefile: moved post section to GNUmakefile.postamble, various + cleanups + + * GNUmakefile.preamble: fixed relative search pathes + +2004-06-02 Marcus Mueller + + * GNUmakefile: more support for building with GNUSTEP_BUILD_DIR + env set (v4.2.20) + +2004-05-05 Marcus Mueller + + * 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 + + * fixed dependencies for Panther (v4.2.18) + +2004-04-07 Helge Hess + + * ODResourceManager.m: fixed a compilation warning (v4.2.17) + +2004-03-09 Helgs Hess + + * 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 + + * 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 + + * ODResourceManager.m: fixed an uninitialized variable (v4.2.14) + +2003-12-20 Helge Hess + + * 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 + + * GNUmakefile: include makefiles from GNUSTEP_MAKEFILES (as suggested + by chunsj@embian.com) (v4.2.12) + +Wed Oct 22 15:19:18 2003 Jan Reichmann + + * GNUmakefile: add ADDITIONAL_LIB_DIRS NGScripting and NGObjWeb + (v4.2.11) + +2003-10-15 Helge Hess + + * some changes for compilation with gstep-make on MacOSX (v4.2.10) + +2003-07-28 Helge Hess + + * applied GNUstep patches provided by Filip Van Raemdonck for improved + compilation with gstep-base (v4.2.9) + +2003-06-30 Helge Hess + + * moved to skyrix-sope-42 (v4.2.8) + +2003-06-18 Helge Hess + + * ODNodeRenderer+attributes.m: added various debugging defaults and + logs, cleanups (v4.1.7) + +2002-11-27 Helge Hess + + * GNUmakefile (SUBPROJECTS): removed WML, not required fuer 4.1 + (v4.1.6) + +2002-08-29 Helge Hess + + * small tweaks to make gcc 3.1 happy + +2002-06-13 Helge Hess + + * WOContext+Cursor.m (WOContext): moved cursor code to NGObjWeb + +2002-06-10 Helge Hess + + * adopted to "new"/current NGJavaScript library + +Fri Jun 7 13:00:36 2002 Helge Hess + + * updated to new "scripting" access + +Mon Dec 17 17:01:59 2001 Helge Hess + + * ODNamespaces.h: use SaxObjC namespace declarations + +Tue Nov 27 15:05:25 2001 Helge Hess + + * added support for HTML40 namespace (as generated by Word 2000) + +Wed Nov 21 17:54:26 2001 Martin Spindler + + * ODR_bind_viewertitle.h: fixed vtitle and vbutton bug + +Wed Oct 17 17:04:12 2001 Helge Hess + + * ODNamespaces.h: added XForms namespace + +Tue Aug 21 14:56:48 2001 Helge Hess + + * ODNodeRenderer+attributes.m: also evaluate JavaScript against the + cursor + +Tue Aug 21 12:24:30 2001 Helge Hess + + * ODNodeRenderer.m: cache parent + +Tue Aug 21 10:52:48 2001 Helge Hess + + * 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 + + * ODNodeRenderer.m: fixed ODProfileRendererMin + +Wed Aug 8 20:36:54 2001 Helge Hess + + * ODNodeRenderer.h: added support for cycle object + +Thu Jul 26 16:43:36 2001 Helge Hess + + * ODNodeRenderer.m: added unique ID generator + +Mon Jul 23 19:40:01 2001 Helge Hess + + * ODNodeRenderer+attributes.m(-invokeValueForAttributeNode:): check + whether return value conforms to WOActionResults protocol, otherwise + return nil + +Mon Jul 9 18:59:05 2001 Helge Hess + + * ODNodeRenderer.m: improved profiling + +Thu Jul 5 19:49:31 2001 Helge Hess + + * ODNodeRenderer.m: added ifnot 'common' attribute + +Wed Jul 4 10:45:46 2001 Helge Hess + + * ODRGenericTag.m ([ODRGenericTag -_appendAttributesOfNode:toResponse:inContext:]): + HTML escape attribute values + +Tue Jul 3 19:02:23 2001 Helge Hess + + * 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 + + * GNUmakefile.preamble: fixed library dependencies + +Wed Jun 6 15:02:57 2001 Helge Hess + + * turned XHTML.subproj and XUL.subproj into bundles + +Mon May 7 12:29:38 2001 Helge Hess + + * ODNodeRenderer.m: added global 'if' attribute + +Sun May 6 16:03:57 2001 Helge Hess + + * XHTML.subproj/ODR_XHTML_input_text.m: added support for disabled + +Fri Mar 30 19:13:59 2001 Helge Hess + + * XHTML.subproj/ODR_XHTML_input.m: added formatting support + +Mon Mar 12 14:14:13 2001 Helge Hess + + * XHTML.subproj/ODRDynamicXHTMLTag.m: use component resource-manager + +Wed Mar 7 16:30:41 2001 Helge Hess + + * 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 + + * added versioning + +Mon Feb 26 20:21:19 2001 Helge Hess + + * 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 index 00000000..6a53797d --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/.cvsignore @@ -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 index 00000000..161a3d1d --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/COPYING @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..f965d7ef --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ChangeLog @@ -0,0 +1,98 @@ +Wed Oct 22 15:57:58 2003 Jan Reichmann + + * GNUmakefile: add ADDITIONAL_LIB_DIRS NGScripting + +Fri Sep 21 18:13:33 2001 Helge Hess + + * 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 + + * ODR_bind_foreach.m: added filtering and sorting + +Tue Aug 21 15:19:45 2001 Helge Hess + + * 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 + + * ODR_bind_form.m ([ODR_bind_form -_childComponentForNode:inContext:]): + register child-forms as subcomponents + +Mon Jul 2 17:38:53 2001 Helge Hess + + * ODR_bind_popupbutton.m: use lowercase 'noselectionstring' instead of + noSelectionString + +Wed Jun 6 14:52:30 2001 Helge Hess + + * added ODR_bind_nbsp to generate HTML nbsp entities ... + +Wed May 16 11:59:18 2001 Helge Hess + + * ODR_bind_datefield.m: better support for calendar-dates, fixed bug + +Mon May 7 20:51:57 2001 Martin Spindler + + * ODR_bind_tableview+Private.m: color was wrong, if no navigation + +Sun May 6 17:12:35 2001 Martin Spindler + + * ODR_bind_tableview+Private.m: render ' ' if no ttitle + +Sun May 6 15:43:02 2001 Helge Hess + + * 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 + + * ODR_bind_tableview+Private.m fixed dataSource bug + +Wed Apr 4 17:16:31 2001 Martin Spindler + + * ODR_bind_tableview+Private.m create copy of fetchSpecification + +Mon Apr 2 18:49:47 2001 Martin Spindler + + * ODR_bind_sortorderings.[h|m]: added + + * ODR_bind_tableview[_private]: changed behaviour of sorting + +Mon Apr 2 11:41:01 2001 Helge Hess + + * ODR_bind_viewertitle.m ([ODR_bind_viewertitle -appendNode:toResponse:inContext:]): + fixed various HTML generation bugs + +Fri Mar 30 18:51:20 2001 Helge Hess + + * ODR_bind_string.m: added support for dateformat, numberformat and nil + +Thu Mar 15 20:06:22 2001 Helge Hess + + * ODR_bind_tableview.m: added selector caching + + * ODR_bind_tableview.m: added profiling + +Thu Mar 8 16:58:47 2001 Helge Hess + + * 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 + + * ODR_bind_tabledata.m: fixed bug with formatter binding + +Fri Feb 23 10:38:08 2001 Helge Hess + + * 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 index 00000000..96988713 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/GNUmakefile @@ -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 index 00000000..ee03b869 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.h @@ -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 + +@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 index 00000000..8199180a --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODBindNodeRenderFactory.m @@ -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 +#include +#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 index 00000000..ed560b0c --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_checkbox.m @@ -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 + +/* + attributes: + + name + checked + value + + example: + + + +*/ + +@interface ODR_bind_checkbox : ODNodeRenderer +@end + +#include +#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:@" 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 index 00000000..59d58528 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_collapsible.m @@ -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 +#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:@""]; + + ODRAppendImage(_response, nil, img, value); + + [_response appendContentString:@""]; + } + + [_ctx deleteLastElementIDComponent]; + + if (label) { + [_response appendContentString:@" "]; + [_response appendContentString:label]; + } + + if (!isCollapsed) { + [_response appendContentString:@"
"]; + [_ctx appendZeroElementIDComponent]; + [self appendChildNodes:[_node childNodes] + toResponse:_response + inContext:_ctx]; + [_ctx deleteLastElementIDComponent]; + } + [_response appendContentString:@"
"]; +} + +@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 index 00000000..2f832cb8 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_datefield.m @@ -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 + +/* + Attributes: + + day - int + month - int + year - int + value - string in format %Y-%m-%d + + Usage: +
+
+*/ + +@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:@""]; + } + [_ctx deleteLastElementIDComponent]; + + [_ctx appendElementIDComponent:@"m"]; + { + static NSString *months[12] = { + @"Jan", @"Feb", @"Mar", @"Apr", @"May", @"Jun", + @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec" + }; + [_response appendContentString:@""]; + } + [_ctx deleteLastElementIDComponent]; + + [_ctx appendElementIDComponent:@"y"]; + { + [_response appendContentString:@""]; + } + [_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 index 00000000..5878cde0 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_fieldset.m @@ -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 +#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:@"']; + [_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:@""]; + + [_ctx deleteLastElementIDComponent]; // delete "t" + [_response appendContentString:@""]; + + [_response appendContentString:@"']; + + [_ctx appendElementIDComponent:@"c"]; + [self appendChildNodes:fields toResponse:_response inContext:_ctx]; + [_ctx deleteLastElementIDComponent]; // delete "c" + [_response appendContentString:@""]; +} + +- (void)appendNode:(id)_node + toResponse:(WOResponse *)_response + inContext:(WOContext *)_ctx +{ + NSArray *fields; + int i, cnt; + + fields = ODRLookupQueryPath(_node, @"field"); + cnt = [fields count]; + + [_response appendContentString: + @""]; + + for (i = 0; i < cnt; i++) { + id field; + + field = [fields objectAtIndex:i]; + + [_ctx appendElementIDComponent:[NSString stringWithFormat:@"%i", i]]; + + [_response appendContentString:@""]; + [self _appendField:field node:_node toResponse:_response inContext:_ctx]; + [_response appendContentString:@""]; + + [_ctx deleteLastElementIDComponent]; // delete index + } + [_response appendContentString:@"
"]; +} + +@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 index 00000000..abb09ef2 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_foreach.m @@ -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: + + + + +*/ + +#include + +@interface ODR_bind_foreach : ODNodeRenderer +@end + +#include "WOContext+Cursor.h" +#include +#include +#include +#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 index 00000000..0592c5c1 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_form.m @@ -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 +#include + +/* + attributes: + + usage: + + + + + + + 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 +#include +#include +#include + +@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 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:@""]; +#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:@""]; +#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 index 00000000..fdb00da9 --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.h @@ -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 + +#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 index 00000000..e0a99e9e --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_groupings.m @@ -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 +#include +#include +#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 index 00000000..e228a8db --- /dev/null +++ b/skyrix-sope/NGObjDOM/Dynamic.subproj/ODR_bind_if.m @@ -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 + +/* + attributes: + condition + value1 + value2 + + usage: + + + + content of if + content of elseif + content of else + + + + + + + + .. + +*/ + +@interface ODR_bind_if : ODNodeRenderer +@end + +@interface ODR_bind_ifnot : ODR_bind_if +@end + +#include +#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 + +/* + attributes: + + list item selection + string + noSelectionString + size + name + + example: + + + + +*/ + +@interface ODR_bind_multiselection : ODNodeRenderer +@end + +@interface ODR_bind_singleselection : ODR_bind_multiselection +@end + +#include +#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:@"