--- sope-4.9.r1664.orig/debian/sope_SOPEVER_-gdl1-postgresql.install +++ sope-4.9.r1664/debian/sope_SOPEVER_-gdl1-postgresql.install @@ -1 +1 @@ -usr/lib/sope-*/dbadaptors/PostgreSQL.gdladaptor +usr/lib/GNUstep/GDLAdaptors-*/PostgreSQL.gdladaptor --- sope-4.9.r1664.orig/debian/libsope-ical_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-ical_SOPEVER_-dev.install @@ -1,2 +1,2 @@ -usr/include/NGiCal +usr/include/GNUstep/NGiCal usr/lib/libNGiCal.so --- sope-4.9.r1664.orig/debian/changelog +++ sope-4.9.r1664/debian/changelog @@ -1,3 +1,28 @@ +sope (4.9.r1664-1) unstable; urgency=low + + * updated SOPE patchset for SOGo 1.2.0. + * updated upstream SOPE revision to 1664. + + -- Inverse Support Wed, 06 Jan 2010 14:49:27 -0500 + +sope (4.9.r1660-2) unstable; urgency=low + + * debian/control: + - we now build the sopeXX-gdl1-mysql package. + * updated SOPE patchset from SOGo 1.1.0. + + -- Inverse Support Mon, 19 Oct 2009 16:36:29 -0400 + +sope (4.9.r1660-1) unstable; urgency=low + + * debian/control: + - updated dependencies + - changed {Source-Version} with {binary:Version} + - bumbed standard to 3.8.2 + - updated debian/copyright with recent LGPL-2 + + -- Inverse Support Wed, 12 Aug 2009 10:34:00 -0400 + sope (4.7.0-0) UNRELEASED; urgency=low * New upstream release. --- sope-4.9.r1664.orig/debian/rules +++ sope-4.9.r1664/debian/rules @@ -7,13 +7,16 @@ #export DH_VERBOSE=1 # Include dpatch stuff. -include /usr/share/dpatch/dpatch.make +# include /usr/share/dpatch/dpatch.make + +PATCHES = sope-gsmake2.diff sope-patchset-r1664.diff debian-build-mysql.diff +RPATCHES = debian-build-mysql.diff sope-patchset-r1664.diff sope-gsmake2.diff CFLAGS = -Wall -g #WARN: doesn't compile/package if HAS_LIBRARY_* options not present (since we use configure now) MAKE_FLAGS = messages=yes OPTFLAG=-O0 HAS_LIBRARY_ldap=yes HAS_LIBRARY_pq=yes HAS_LIBRARY_xml2=yes -GNUSTEP_SETUP=/usr/lib/opengroupware.org/System/Library/Makefiles/GNUstep.sh +GNUSTEP_SETUP=/usr/share/GNUstep/Makefiles/GNUstep.sh include Version SOPEVER=$(MAJOR_VERSION).$(MINOR_VERSION) @@ -50,17 +53,17 @@ done; \ rm controlfiles.tmp; \ fi - + debian/control: debian/control.in debian/rules sed -e s/_SOPEVER_/$(SOPEVER)/g < debian/control.in > debian/control -config.status: configure +config.make: patch-stamp dh_testdir CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ - ./configure - -build: build-stamp controlfiles -build-stamp: patch-stamp + ./configure --with-gnustep --enable-debug --disable-strip + +build: config.make build-stamp controlfiles +build-stamp: dh_testdir -mv sope-core/NGStreams/config.guess sope-core/NGStreams/config.guess.upstream @@ -71,14 +74,14 @@ CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ $(MAKE) $(MAKE_FLAGS) all - cp -R sope-appserver/mod_ngobjweb sope-appserver/mod_ngobjweb-apache2 +# cp -R sope-appserver/mod_ngobjweb sope-appserver/mod_ngobjweb-apache2 - CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ - $(MAKE) $(MAKE_FLAGS) APXS=/usr/bin/apxs -C sope-appserver/mod_ngobjweb all - - CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ - $(MAKE) $(MAKE_FLAGS) APXS="/usr/bin/apxs2" APXS_INCLUDE_DIRS="$(shell apxs2 -q EXTRA_INCLUDES)"\ - -C sope-appserver/mod_ngobjweb-apache2 all +# CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ +# $(MAKE) $(MAKE_FLAGS) APXS=/usr/bin/apxs -C sope-appserver/mod_ngobjweb all + +# CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ +# $(MAKE) $(MAKE_FLAGS) APXS="/usr/bin/apxs2" APXS_INCLUDE_DIRS="$(shell apxs2 -q EXTRA_INCLUDES)"\ +# -C sope-appserver/mod_ngobjweb-apache2 all touch build-stamp @@ -87,12 +90,14 @@ dh_testroot rm -f configure-stamp rm -f build-stamp + rm -f config-NSStreams.log rm -rf sope-appserver/mod_ngobjweb-apache2 + rm -rf sope-core/NGStreams/x86_64 - if [ -l sope-core/NGStreams/config.guess ]; then \ + if [ -L sope-core/NGStreams/config.guess ]; then \ rm sope-core/NGStreams/config.guess; \ fi - if [ -l sope-core/NGStreams/config.sub ]; then \ + if [ -L sope-core/NGStreams/config.sub ]; then \ rm sope-core/NGStreams/config.sub; \ fi if [ -f sope-core/NGStreams/config.guess.upstream ]; then \ @@ -102,8 +107,8 @@ mv sope-core/NGStreams/config.sub.upstream sope-core/NGStreams/config.sub; \ fi - -. $(GNUSTEP_SETUP); $(MAKE) -C sope-appserver/mod_ngobjweb clean - -. $(GNUSTEP_SETUP); $(MAKE) -C sope-appserver/mod_ngobjweb distclean +# -. $(GNUSTEP_SETUP); $(MAKE) -C sope-appserver/mod_ngobjweb clean +# -. $(GNUSTEP_SETUP); $(MAKE) -C sope-appserver/mod_ngobjweb distclean -. $(GNUSTEP_SETUP); $(MAKE) clean -. $(GNUSTEP_SETUP); $(MAKE) distclean @@ -116,24 +121,24 @@ dh_clean -k dh_installdirs - # Add here commands to install the package into debian/tmp +# Add here commands to install the package into debian/tmp CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ $(MAKE) $(MAKE_FLAGS) install \ - GNUSTEP_INSTALLATION_DIR=$(CURDIR)/debian/tmp/$$GNUSTEP_SYSTEM_ROOT\ - INSTALL_ROOT_DIR=$(CURDIR)/debian/tmp\ + DESTDIR=$(CURDIR)/debian/tmp GNUSTEP_INSTALLATION_DOMAIN=SYSTEM +# INSTALL_ROOT_DIR=$(CURDIR)/debian/tmp\ FHS_INSTALL_ROOT=$(CURDIR)/debian/tmp/usr \ FHS_LIB_DIR=$(CURDIR)/debian/tmp/usr/lib/ #WARN: <- trailing slash unbroke build/packages?! - CFLAGS="$(CFLGAS)" . $(GNUSTEP_SETUP); \ +# CFLAGS="$(CFLGAS)" . $(GNUSTEP_SETUP); \ $(MAKE) $(MAKE_FLAGS) -C sope-appserver/mod_ngobjweb install \ - GNUSTEP_INSTALLATION_DIR=$(CURDIR)/debian/tmp/usr/lib/apache/1.3 + GNUSTEP_INSTALLATION_DOMAIN=$(CURDIR)/debian/tmp/usr/lib/apache/1.3 - CFLAGS="$(CFLGAS)" . $(GNUSTEP_SETUP); \ +# CFLAGS="$(CFLGAS)" . $(GNUSTEP_SETUP); \ $(MAKE) $(MAKE_FLAGS) -C sope-appserver/mod_ngobjweb-apache2 install \ - GNUSTEP_INSTALLATION_DIR=$(CURDIR)/debian/tmp/usr/lib/apache2/modules + GNUSTEP_INSTALLATION_DOMAIN=$(CURDIR)/debian/tmp/usr/lib/apache2/modules - install -m 644 debian/500mod_ngobjweb.info $(CURDIR)/debian/libapache-mod-ngobjweb/usr/lib/apache/1.3 - install -m 644 debian/ngobjweb.load $(CURDIR)/debian/libapache2-mod-ngobjweb/etc/apache2/mods-available +# install -m 644 debian/500mod_ngobjweb.info $(CURDIR)/debian/libapache-mod-ngobjweb/usr/lib/apache/1.3 +# install -m 644 debian/ngobjweb.load $(CURDIR)/debian/libapache2-mod-ngobjweb/etc/apache2/mods-available # Build architecture-independent files here. binary-indep: build install @@ -172,5 +177,28 @@ dh_md5sums dh_builddeb +patch-stamp: patch +patch: + for patch in $(PATCHES); \ + do \ + if ! test -f debian/patches/$$patch.stamp; \ + then \ + patch -p0 < debian/patches/$$patch; \ + touch debian/patches/$$patch.stamp; \ + fi; \ + done + touch patch-stamp + +unpatch: + if test -f patch-stamp; \ + then \ + for patch in $(RPATCHES); \ + do \ + patch -p0 -R < debian/patches/$$patch; \ + rm -f debian/patches/$$patch.stamp; \ + done; \ + rm -f patch-stamp; \ + fi + binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure --- sope-4.9.r1664.orig/debian/sope_SOPEVER_-libxmlsaxdriver.install +++ sope-4.9.r1664/debian/sope_SOPEVER_-libxmlsaxdriver.install @@ -1 +1 @@ -usr/lib/sope-*/saxdrivers/libxmlSAXDriver.sax +usr/lib/GNUstep/SaxDrivers-*/libxmlSAXDriver.sax --- sope-4.9.r1664.orig/debian/sope_SOPEVER_-gdl1-mysql.install +++ sope-4.9.r1664/debian/sope_SOPEVER_-gdl1-mysql.install @@ -0,0 +1 @@ +usr/lib/GNUstep/GDLAdaptors-*/MySQL.gdladaptor --- sope-4.9.r1664.orig/debian/control.in +++ sope-4.9.r1664/debian/control.in @@ -1,8 +1,9 @@ Source: sope +Section: web Priority: extra -Maintainer: Sebastian Ley -Build-Depends: debhelper (>= 4.0.0), dpatch, gnustep-make-ogo, gobjc | objc-compiler, libfoundation1.1-dev, libobjc1, libxml2-dev, libldap2-dev | libldap-dev, libssl-dev, zlib1g-dev, libpq-dev | postgresql-dev, libecpg-dev, apache-dev, apache2-threaded-dev | apache2-prefork-dev | apache2-dev, autotools-dev -Standards-Version: 3.6.1 +Maintainer: Inverse Support +Build-Depends: debhelper (>= 4.0.0), gnustep-make, libgnustep-base-dev, gobjc | objc-compiler, libxml2-dev, libldap2-dev | libldap-dev, libssl-dev, zlib1g-dev, libpq-dev | postgresql-dev, libmysqlclient-dev (>= 5.0) | libmysqlclient15-dev (>= 5.0), autotools-dev +Standards-Version: 3.8.2 Package: libsope_SOPEVER_-dev Section: libdevel @@ -22,7 +23,7 @@ Architecture: any Provides: libsope-appserver-dev Conflicts: libsope-appserver-dev -Depends: libsope-appserver_SOPEVER_ (= ${Source-Version}) +Depends: libsope-appserver_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -75,7 +76,7 @@ Architecture: any Provides: libsope-core-dev Conflicts: libsope-core-dev -Depends: libsope-core_SOPEVER_ (= ${Source-Version}) +Depends: libsope-core_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE core libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -98,7 +99,7 @@ Architecture: any Provides: libsope-xml-dev Conflicts: libsope-xml-dev -Depends: libsope-xml_SOPEVER_ (= ${Source-Version}) +Depends: libsope-xml_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE XML libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -125,7 +126,7 @@ Architecture: any Provides: libsope-ldap-dev Conflicts: libsope-ldap-dev -Depends: libsope-ldap_SOPEVER_ (= ${Source-Version}) +Depends: libsope-ldap_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE LDAP libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -149,7 +150,7 @@ Architecture: any Provides: libsope-mime-dev Conflicts: libsope-mime-dev -Depends: libsope-mime_SOPEVER_ (= ${Source-Version}) +Depends: libsope-mime_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE MIME libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -176,7 +177,7 @@ Architecture: any Provides: libsope-ical-dev Conflicts: libsope-ical-dev -Depends: libsope-ical_SOPEVER_ (= ${Source-Version}) +Depends: libsope-ical_SOPEVER_ (= ${binary:Version}) Description: Development files for the SOPE iCal libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -200,7 +201,7 @@ Architecture: any Provides: libsope-gdl1-dev Conflicts: libsope-gdl1-dev -Depends: libsope-gdl1-_SOPEVER_ (= ${Source-Version}) +Depends: libsope-gdl1-_SOPEVER_ (= ${binary:Version}) Description: Development files for the GNUstep database libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -223,15 +224,28 @@ Section: web Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: sope-db-connector -Recommends: postgresql (>= 7.2.0) +Provides: sope_SOPEVER_-db-connector +Suggests: postgresql (>= 8.2) Description: PostgreSQL connector for SOPE's fork of the GNUstep database environment SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. . This package contains the postgresql connector for SOPE's fork of the GNUstep database libraries. - + +Package: sope_SOPEVER_-gdl1-mysql +Section: web +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Provides: sope_SOPEVER_-db-connector +Recommends: mysql-server (>= 5.0) +Description: MySQL connector for SOPE's fork of the GNUstep database environment + SOPE is a framework for developing web applications and services. The + name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. + . + This package contains the mysql connector for SOPE's fork of the + GNUstep database libraries. + Package: sope_SOPEVER_-stxsaxdriver Section: web Architecture: any @@ -264,19 +278,3 @@ name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. . This parser enables SOPE's SAX engine to parse iCal and vCard files. - -Package: libapache-mod-ngobjweb -Section: web -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ucf (>= 0.8), apache-common (>= 1.3.29) -Description: Apache module for the SOPE application server - This package contains an apache module which enables the apache - webserver to deliver pages generated by the SOPE application server. - -Package: libapache2-mod-ngobjweb -Section: web -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, apache2-common | apache2.2-common -Description: Apache2 module for the SOPE application server - This package contains an apache module which enables the apache2 - webserver to deliver pages generated by the SOPE application server. --- sope-4.9.r1664.orig/debian/libsope-ical_SOPEVER_.install +++ sope-4.9.r1664/debian/libsope-ical_SOPEVER_.install @@ -1,2 +1,2 @@ usr/lib/libNGiCal.so.* -usr/share/sope-*/saxmappings +usr/lib/GNUstep/SaxMappings/* --- sope-4.9.r1664.orig/debian/libsope-core_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-core_SOPEVER_-dev.install @@ -1,6 +1,6 @@ -usr/include/NGExtensions -usr/include/EOControl -usr/include/NGStreams +usr/include/GNUstep/NGExtensions +usr/include/GNUstep/EOControl +usr/include/GNUstep/NGStreams usr/lib/libNGExtensions.so usr/lib/libEOControl.so usr/lib/libNGStreams.so --- sope-4.9.r1664.orig/debian/sope_SOPEVER_-stxsaxdriver.install +++ sope-4.9.r1664/debian/sope_SOPEVER_-stxsaxdriver.install @@ -1 +1 @@ -usr/lib/sope-*/saxdrivers/STXSaxDriver.sax +usr/lib/GNUstep/SaxDrivers-*/STXSaxDriver.sax --- sope-4.9.r1664.orig/debian/compat +++ sope-4.9.r1664/debian/compat @@ -1 +1 @@ -4 +5 --- sope-4.9.r1664.orig/debian/libsope-mime_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-mime_SOPEVER_-dev.install @@ -1,4 +1,4 @@ -usr/include/NGMime -usr/include/NGImap4 -usr/include/NGMail +usr/include/GNUstep/NGMime +usr/include/GNUstep/NGImap4 +usr/include/GNUstep/NGMail usr/lib/libNGMime.so --- sope-4.9.r1664.orig/debian/copyright +++ sope-4.9.r1664/debian/copyright @@ -8,19 +8,19 @@ License: - This package is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public + 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 package is distributed in the hope that it will be useful, + 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 - Lesser General Public License for more details. + Library General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this package; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA On Debian systems, the complete text of the GNU Lesser General Public License can be found in `/usr/share/common-licenses/LGPL'. --- sope-4.9.r1664.orig/debian/libsope-appserver_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-appserver_SOPEVER_-dev.install @@ -1,11 +1,10 @@ -usr/include/NGHttp -usr/include/NGObjWeb -usr/include/WOXML -usr/include/WOExtensions -usr/include/WEExtensions -usr/include/NGXmlRpc -usr/include/SoOFS -usr/lib/opengroupware.org/System/Library/Makefiles +usr/include/GNUstep/NGHttp +usr/include/GNUstep/NGObjWeb +usr/include/GNUstep/WOXML +usr/include/GNUstep/WOExtensions +usr/include/GNUstep/WEExtensions +usr/include/GNUstep/NGXmlRpc +usr/include/GNUstep/SoOFS usr/lib/libNGObjWeb.so usr/lib/libWOXML.so usr/lib/libWOExtensions.so @@ -13,3 +12,4 @@ usr/lib/libNGXmlRpc.so usr/lib/libSoOFS.so usr/lib/libWEPrototype.so +usr/share/GNUstep/Makefiles/* --- sope-4.9.r1664.orig/debian/control +++ sope-4.9.r1664/debian/control @@ -1,8 +1,9 @@ Source: sope +Section: web Priority: extra -Maintainer: Sebastian Ley -Build-Depends: debhelper (>= 4.0.0), dpatch, gnustep-make-ogo, gobjc | objc-compiler, libfoundation1.1-dev, libobjc1, libxml2-dev, libldap2-dev | libldap-dev, libssl-dev, zlib1g-dev, libpq-dev | postgresql-dev, libecpg-dev, apache-dev, apache2-threaded-dev | apache2-prefork-dev | apache2-dev, autotools-dev -Standards-Version: 3.6.1 +Maintainer: Inverse Support +Build-Depends: debhelper (>= 4.0.0), gnustep-make, libgnustep-base-dev, gobjc | objc-compiler, libxml2-dev, libldap2-dev | libldap-dev, libssl-dev, zlib1g-dev, libpq-dev | postgresql-dev, libmysqlclient-dev (>= 5.0) | libmysqlclient15-dev (>= 5.0), autotools-dev +Standards-Version: 3.8.2 Package: libsope4.9-dev Section: libdevel @@ -22,7 +23,7 @@ Architecture: any Provides: libsope-appserver-dev Conflicts: libsope-appserver-dev -Depends: libsope-appserver4.9 (= ${Source-Version}) +Depends: libsope-appserver4.9 (= ${binary:Version}) Description: Development files for the SOPE libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -75,7 +76,7 @@ Architecture: any Provides: libsope-core-dev Conflicts: libsope-core-dev -Depends: libsope-core4.9 (= ${Source-Version}) +Depends: libsope-core4.9 (= ${binary:Version}) Description: Development files for the SOPE core libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -98,7 +99,7 @@ Architecture: any Provides: libsope-xml-dev Conflicts: libsope-xml-dev -Depends: libsope-xml4.9 (= ${Source-Version}) +Depends: libsope-xml4.9 (= ${binary:Version}) Description: Development files for the SOPE XML libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -125,7 +126,7 @@ Architecture: any Provides: libsope-ldap-dev Conflicts: libsope-ldap-dev -Depends: libsope-ldap4.9 (= ${Source-Version}) +Depends: libsope-ldap4.9 (= ${binary:Version}) Description: Development files for the SOPE LDAP libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -149,7 +150,7 @@ Architecture: any Provides: libsope-mime-dev Conflicts: libsope-mime-dev -Depends: libsope-mime4.9 (= ${Source-Version}) +Depends: libsope-mime4.9 (= ${binary:Version}) Description: Development files for the SOPE MIME libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -176,7 +177,7 @@ Architecture: any Provides: libsope-ical-dev Conflicts: libsope-ical-dev -Depends: libsope-ical4.9 (= ${Source-Version}) +Depends: libsope-ical4.9 (= ${binary:Version}) Description: Development files for the SOPE iCal libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -200,7 +201,7 @@ Architecture: any Provides: libsope-gdl1-dev Conflicts: libsope-gdl1-dev -Depends: libsope-gdl1-4.9 (= ${Source-Version}) +Depends: libsope-gdl1-4.9 (= ${binary:Version}) Description: Development files for the GNUstep database libraries SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. @@ -223,15 +224,28 @@ Section: web Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: sope-db-connector -Recommends: postgresql (>= 7.2.0) +Provides: sope4.9-db-connector +Suggests: postgresql (>= 8.2) Description: PostgreSQL connector for SOPE's fork of the GNUstep database environment SOPE is a framework for developing web applications and services. The name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. . This package contains the postgresql connector for SOPE's fork of the GNUstep database libraries. - + +Package: sope4.9-gdl1-mysql +Section: web +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Provides: sope4.9-db-connector +Recommends: mysql-server (>= 5.0) +Description: MySQL connector for SOPE's fork of the GNUstep database environment + SOPE is a framework for developing web applications and services. The + name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. + . + This package contains the mysql connector for SOPE's fork of the + GNUstep database libraries. + Package: sope4.9-stxsaxdriver Section: web Architecture: any @@ -264,19 +278,3 @@ name "SOPE" (SKYRiX Object Publishing Environment) is inspired by ZOPE. . This parser enables SOPE's SAX engine to parse iCal and vCard files. - -Package: libapache-mod-ngobjweb -Section: web -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, ucf (>= 0.8), apache-common (>= 1.3.29) -Description: Apache module for the SOPE application server - This package contains an apache module which enables the apache - webserver to deliver pages generated by the SOPE application server. - -Package: libapache2-mod-ngobjweb -Section: web -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, apache2-common | apache2.2-common -Description: Apache2 module for the SOPE application server - This package contains an apache module which enables the apache2 - webserver to deliver pages generated by the SOPE application server. --- sope-4.9.r1664.orig/debian/libsope-xml_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-xml_SOPEVER_-dev.install @@ -1,6 +1,6 @@ -usr/include/DOM -usr/include/SaxObjC -usr/include/XmlRpc +usr/include/GNUstep/DOM +usr/include/GNUstep/SaxObjC +usr/include/GNUstep/XmlRpc usr/lib/libDOM.so usr/lib/libSaxObjC.so usr/lib/libXmlRpc.so --- sope-4.9.r1664.orig/debian/sope_SOPEVER_-versitsaxdriver.install +++ sope-4.9.r1664/debian/sope_SOPEVER_-versitsaxdriver.install @@ -1 +1 @@ -usr/lib/sope-*/saxdrivers/versitSaxDriver.sax +usr/lib/GNUstep/SaxDrivers-*/versitSaxDriver.sax --- sope-4.9.r1664.orig/debian/libsope-gdl1-_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-gdl1-_SOPEVER_-dev.install @@ -1,2 +1,2 @@ -usr/include/GDLAccess +usr/include/GNUstep/GDLAccess usr/lib/libGDLAccess.so --- sope-4.9.r1664.orig/debian/libsope-ldap_SOPEVER_-dev.install +++ sope-4.9.r1664/debian/libsope-ldap_SOPEVER_-dev.install @@ -1,2 +1,2 @@ -usr/include/NGLdap +usr/include/GNUstep/NGLdap usr/lib/libNGLdap.so --- sope-4.9.r1664.orig/debian/libsope-appserver_SOPEVER_.install +++ sope-4.9.r1664/debian/libsope-appserver_SOPEVER_.install @@ -5,6 +5,6 @@ usr/lib/libNGXmlRpc.so.* usr/lib/libSoOFS.so.* usr/lib/libWEPrototype.so.* -usr/share/sope-*/ngobjweb -usr/lib/sope-*/products -usr/lib/sope-*/wox-builders +usr/lib/GNUstep/Libraries/Resources/NGObjWeb/* +usr/lib/GNUstep/SoProducts-*/* +usr/lib/GNUstep/WOxElemBuilders-*/* --- sope-4.9.r1664.orig/debian/patches/sope-patchset-r1664.diff +++ sope-4.9.r1664/debian/patches/sope-patchset-r1664.diff @@ -0,0 +1,7726 @@ +Index: sope-ldap/NGLdap/NGLdapEntry.m +=================================================================== +--- sope-ldap/NGLdap/NGLdapEntry.m (revision 1664) ++++ sope-ldap/NGLdap/NGLdapEntry.m (working copy) +@@ -105,14 +105,16 @@ + - (NGLdapAttribute *)attributeWithName:(NSString *)_name { + NSEnumerator *e; + NGLdapAttribute *a; +- ++ NSString *upperName; ++ + if (_name == nil) + return nil; + ++ upperName = [_name uppercaseString]; + e = [self->attributes objectEnumerator]; + + while ((a = [e nextObject])) { +- if ([[a attributeName] isEqualToString:_name]) ++ if ([[[a attributeName] uppercaseString] isEqualToString:upperName]) + return a; + } + return nil; +Index: sope-ldap/NGLdap/ChangeLog +=================================================================== +--- sope-ldap/NGLdap/ChangeLog (revision 1664) ++++ sope-ldap/NGLdap/ChangeLog (working copy) +@@ -1,3 +1,8 @@ ++2009-08-13 Wolfgang Sourdeau ++ ++ * NGLdapEntry.m (-attributeWithName:): attribute names are now ++ accessed in a case-insensitive way. ++ + 2009-04-02 Wolfgang Sourdeau + + * NGLdapConnection.m (useSSL,startTLS): new method enabling +Index: sope-gdl1/PostgreSQL/PostgreSQL72Channel.m +=================================================================== +--- sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (revision 1664) ++++ sope-gdl1/PostgreSQL/PostgreSQL72Channel.m (working copy) +@@ -713,6 +713,39 @@ + return ms; + } + ++/* GCSEOAdaptorChannel protocol */ ++static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" ++ @" c_content VARCHAR (100000) NOT NULL,\n" ++ @" c_creationdate INT4 NOT NULL,\n" ++ @" c_lastmodified INT4 NOT NULL,\n" ++ @" c_version INT4 NOT NULL,\n" ++ @" c_deleted INT4 NULL\n" ++ @")"); ++static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_uid VARCHAR (256) NOT NULL,\n" ++ @" c_object VARCHAR (256) NOT NULL,\n" ++ @" c_role VARCHAR (80) NOT NULL\n" ++ @")"); ++ ++- (NSException *) createGCSFolderTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ ++- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ + @end /* PostgreSQL72Channel */ + + @implementation PostgreSQL72Channel(PrimaryKeyGeneration) +Index: sope-gdl1/MySQL/MySQL4Channel.m +=================================================================== +--- sope-gdl1/MySQL/MySQL4Channel.m (revision 1664) ++++ sope-gdl1/MySQL/MySQL4Channel.m (working copy) +@@ -755,6 +755,39 @@ + return pkey; + } + ++/* GCSEOAdaptorChannel protocol */ ++static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_name VARCHAR (256) NOT NULL PRIMARY KEY,\n" ++ @" c_content VARCHAR (100000) NOT NULL,\n" ++ @" c_creationdate INT NOT NULL,\n" ++ @" c_lastmodified INT NOT NULL,\n" ++ @" c_version INT NOT NULL,\n" ++ @" c_deleted INT NULL\n" ++ @")"); ++static NSString *sqlFolderACLFormat = (@"CREATE TABLE %@ (\n" \ ++ @" c_uid VARCHAR (256) NOT NULL,\n" ++ @" c_object VARCHAR (256) NOT NULL,\n" ++ @" c_role VARCHAR (80) NOT NULL\n" ++ @")"); ++ ++- (NSException *) createGCSFolderTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ ++- (NSException *) createGCSFolderACLTableWithName: (NSString *) tableName ++{ ++ NSString *sql; ++ ++ sql = [NSString stringWithFormat: sqlFolderACLFormat, tableName]; ++ ++ return [self evaluateExpressionX: sql]; ++} ++ + @end /* MySQL4Channel */ + + void __link_MySQL4Channel() { +Index: sope-gdl1/Oracle8/OracleAdaptorChannel.m +=================================================================== +--- sope-gdl1/Oracle8/OracleAdaptorChannel.m (revision 1664) ++++ sope-gdl1/Oracle8/OracleAdaptorChannel.m (working copy) +@@ -1,7 +1,7 @@ + /* + ** OracleAdaptorChannel.m + ** +-** Copyright (c) 2007 Inverse groupe conseil inc. and Ludovic Marcotte ++** Copyright (c) 2007-2009 Inverse inc. and Ludovic Marcotte + ** + ** Author: Ludovic Marcotte + ** +@@ -30,6 +30,11 @@ + + #import + ++#include ++ ++static BOOL debugOn = NO; ++static int maxTry = 3; ++static int maxSleep = 500; + // + // + // +@@ -41,10 +46,11 @@ + + @implementation OracleAdaptorChannel (Private) + +-- (void) _cleanup ++- (void) _cleanup + { + column_info *info; + int c; ++ sword result; + + [_resultSetProperties removeAllObjects]; + +@@ -58,11 +64,29 @@ + // so we just free the value instead. + if (info->value) + { +- if (OCIDescriptorFree((dvoid *)info->value, (ub4)OCI_DTYPE_LOB) != OCI_SUCCESS) ++ if (info->type == SQLT_CLOB ++ || info->type == SQLT_BLOB ++ || info->type == SQLT_BFILEE ++ || info->type == SQLT_CFILEE) ++ { ++ result = OCIDescriptorFree((dvoid *)info->value, (ub4) OCI_DTYPE_LOB); ++ if (result != OCI_SUCCESS) ++ { ++ NSLog (@"value was not a LOB descriptor"); ++ abort(); ++ } ++ } ++ else + free(info->value); + info->value = NULL; + } +- free(info); ++ else ++ { ++ NSLog (@"trying to free an already freed value!"); ++ abort(); ++ } ++ free(info); ++ + [_row_buffer removeObjectAtIndex: c]; + } + +@@ -78,8 +102,7 @@ + // + @implementation OracleAdaptorChannel + +-static void +-DBTerminate() ++static void DBTerminate() + { + if (OCITerminate(OCI_DEFAULT)) + NSLog(@"FAILED: OCITerminate()"); +@@ -89,6 +112,11 @@ + + + (void) initialize + { ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; ++ + // We Initialize the OCI process environment. + if (OCIInitialize((ub4)OCI_DEFAULT, (dvoid *)0, + (dvoid * (*)(dvoid *, size_t)) 0, +@@ -156,14 +184,17 @@ + [super closeChannel]; + + // We logoff from the database. +- if (OCILogoff(_oci_ctx, _oci_err)) ++ if (!_oci_ctx || !_oci_err || OCILogoff(_oci_ctx, _oci_err)) + { + NSLog(@"FAILED: OCILogoff()"); + } + ++ if (_oci_ctx) ++ OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); + +- OCIHandleFree(_oci_ctx, OCI_HTYPE_SVCCTX); +- OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); ++ if (_oci_err) ++ OCIHandleFree(_oci_err, OCI_HTYPE_ERROR); ++ + // OCIHandleFree(_oci_env, OCI_HTYPE_ENV); + + _oci_ctx = (OCISvcCtx *)0; +@@ -177,7 +208,8 @@ + // + - (void) dealloc + { +- //NSLog(@"OracleAdaptorChannel: -dealloc"); ++ if (debugOn) ++ NSLog(@"OracleAdaptorChannel: -dealloc"); + + [self _cleanup]; + +@@ -222,7 +254,7 @@ + { + EOAttribute *attribute; + OCIParam *param; +- ++ int rCount; + column_info *info; + ub4 i, clen, count; + text *sql, *cname; +@@ -231,6 +263,9 @@ + + [self _cleanup]; + ++ if (debugOn) ++ [self logWithFormat: @"expression: %@", theExpression]; ++ + if (!theExpression || ![theExpression length]) + { + [NSException raise: @"OracleInvalidExpressionException" +@@ -244,7 +279,9 @@ + } + + sql = (text *)[theExpression UTF8String]; +- ++ ++ rCount = 0; ++ retry: + // We alloc our statement handle + if ((status = OCIHandleAlloc((dvoid *)_oci_env, (dvoid **)&_current_stm, (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))) + { +@@ -264,13 +301,39 @@ + // We check if we're doing a SELECT and if so, we're fetching data! + OCIAttrGet(_current_stm, OCI_HTYPE_STMT, &type, 0, OCI_ATTR_STMT_TYPE, _oci_err); + self->isFetchInProgress = (type == OCI_STMT_SELECT ? YES : NO); +- ++ + // We execute our statement. Not that we _MUST_ set iter to 0 for non-SELECT statements. + if ((status = OCIStmtExecute(_oci_ctx, _current_stm, _oci_err, (self->isFetchInProgress ? (ub4)0 : (ub4)1), (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, + ([(OracleAdaptorContext *)[self adaptorContext] autoCommit] ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT)))) + { ++ ub4 serverStatus; ++ + checkerr(_oci_err, status); + NSLog(@"Statement execute failed (OCI_ERROR): %@", theExpression); ++ ++ // We check to see if we lost connection and need to reconnect. ++ serverStatus = 0; ++ OCIAttrGet((dvoid *)_oci_env, OCI_HTYPE_SERVER, (dvoid *)&serverStatus, (ub4 *)0, OCI_ATTR_SERVER_STATUS, _oci_err); ++ ++ if (serverStatus == OCI_SERVER_NOT_CONNECTED) ++ { ++ // We cleanup our previous handles ++ [self cancelFetch]; ++ [self closeChannel]; ++ ++ // We try to reconnect a couple of times before giving up... ++ while (rCount < maxTry) ++ { ++ usleep(maxSleep); ++ rCount++; ++ ++ if ([self openChannel]) ++ { ++ NSLog(@"Connection re-established to Oracle - retrying to process the statement."); ++ goto retry; ++ } ++ } ++ } + return NO; + } + +@@ -302,7 +365,9 @@ + // We read the maximum width of a column + info->max_width = 0; + status = OCIAttrGet((dvoid*)param, (ub4)OCI_DTYPE_PARAM, (dvoid*)&(info->max_width), (ub4 *)0, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)_oci_err); +- ++ ++ if (debugOn) ++ NSLog(@"name: %s, type: %d", cname, info->type); + attribute = [EOAttribute attributeWithOracleType: info->type name: cname length: clen width: info->max_width]; + [_resultSetProperties addObject: attribute]; + +@@ -394,16 +459,17 @@ + return NO; + } + +- + if (OCIEnvInit((OCIEnv **)&_oci_env, (ub4)OCI_DEFAULT, (size_t)0, (dvoid **)0)) + { + NSLog(@"FAILED: OCIEnvInit()"); ++ [self closeChannel]; + return NO; + } + + if (OCIHandleAlloc((dvoid *)_oci_env, (dvoid *)&_oci_err, (ub4)OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0)) + { + NSLog(@"FAILED: OCIHandleAlloc() on errhp"); ++ [self closeChannel]; + return NO; + } + +@@ -414,7 +480,10 @@ + // Under Oracle 10g, the third parameter of OCILogon() has the form: [//]host[:port][/service_name] + // See http://download-west.oracle.com/docs/cd/B12037_01/network.101/b10775/naming.htm#i498306 for + // all juicy details. +- database = [[NSString stringWithFormat:@"%@:%@", [o serverName], [o port]] UTF8String]; ++ if ([o serverName] && [o port]) ++ database = [[NSString stringWithFormat:@"%@:%@/%@", [o serverName], [o port], [o databaseName]] UTF8String]; ++ else ++ database = [[o databaseName] UTF8String]; + + // We logon to the database. + if (OCILogon(_oci_env, _oci_err, &_oci_ctx, (const OraText*)username, strlen(username), +@@ -422,6 +491,7 @@ + { + NSLog(@"FAILED: OCILogon(). username = %s password = %s" + @" database = %s", username, password, database); ++ [self closeChannel]; + return NO; + } + +@@ -438,6 +508,11 @@ + { + sword status; + ++ // We check if our connection is open prior to trying to fetch any data. OCIStmtFetch2() returns ++ // NO error code if the OCI environment is set up but the OCILogon() has failed. ++ if (![self isOpen]) ++ return nil; ++ + status = OCIStmtFetch2(_current_stm, _oci_err, (ub4)1, (ub4)OCI_FETCH_NEXT, (sb4)0, (ub4)OCI_DEFAULT); + + if (status == OCI_NO_DATA) +@@ -609,7 +684,7 @@ + + /* GCSEOAdaptorChannel protocol */ + static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" \ +- @" c_name VARCHAR2 (256) NOT NULL,\n" ++ @" c_name VARCHAR2 (256) NOT NULL PRIMARY KEY,\n" + @" c_content CLOB NOT NULL,\n" + @" c_creationdate INTEGER NOT NULL,\n" + @" c_lastmodified INTEGER NOT NULL,\n" +Index: sope-gdl1/Oracle8/OracleAdaptorChannelController.m +=================================================================== +--- sope-gdl1/Oracle8/OracleAdaptorChannelController.m (revision 1664) ++++ sope-gdl1/Oracle8/OracleAdaptorChannelController.m (working copy) +@@ -31,6 +31,8 @@ + #import + #import + ++static BOOL debugOn = NO; ++ + // + // + // +@@ -48,6 +50,14 @@ + // + @implementation OracleAdaptorChannelController + +++ (void) initialize ++{ ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ debugOn = [ud boolForKey: @"OracleAdaptorDebug"]; ++} ++ + - (EODelegateResponse) adaptorChannel: (id) theChannel + willInsertRow: (NSMutableDictionary *) theRow + forEntity: (EOEntity *) theEntity +@@ -56,7 +66,8 @@ + NSArray *keys; + int i, c; + +- NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); ++ if (debugOn) ++ NSLog(@"willInsertRow: %@ %@", [theRow description], [theEntity description]); + + s = AUTORELEASE([[NSMutableString alloc] init]); + +@@ -101,7 +112,8 @@ + NSArray *keys; + int i, c; + +- NSLog(@"willUpdatetRow: %@ %@", [theRow description], [theQualifier description]); ++ if (debugOn) ++ NSLog(@"willUpdateRow: %@ %@", [theRow description], [theQualifier description]); + + s = AUTORELEASE([[NSMutableString alloc] init]); + +Index: sope-mime/NGImap4/NGImap4Functions.m +=================================================================== +--- sope-mime/NGImap4/NGImap4Functions.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4Functions.m (working copy) +@@ -367,3 +367,16 @@ + } + + @end /* NGImap4FolderHandler */ ++ ++NSString * ++SaneFolderName(NSString *folderName) ++{ ++ NSString *saneFName; ++ ++ saneFName = [[folderName stringByReplacingString: @"\\" ++ withString: @"\\\\"] ++ stringByReplacingString: @"\"" ++ withString: @"\\\""]; ++ ++ return saneFName; ++} +Index: sope-mime/NGImap4/NGImap4Client.h +=================================================================== +--- sope-mime/NGImap4/NGImap4Client.h (revision 1664) ++++ sope-mime/NGImap4/NGImap4Client.h (working copy) +@@ -62,6 +62,8 @@ + NGImap4ResponseNormalizer *normer; + NSMutableArray *responseReceiver; + ++ BOOL loggedIn; ++ + BOOL isLogin; + unsigned tagId; + +@@ -117,9 +119,11 @@ + - (NSDictionary *)noop; + + - (NSDictionary *)capability; ++- (NSDictionary *)namespace; + - (NSDictionary *)list:(NSString *)_folder pattern:(NSString *)_pattern; + - (NSDictionary *)lsub:(NSString *)_folder pattern:(NSString *)_pattern; + - (NSDictionary *)select:(NSString *)_folder; ++- (NSDictionary *)unselect; + - (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags; + - (NSDictionary *)rename:(NSString *)_folder to:(NSString *)_newName; + - (NSDictionary *)delete:(NSString *)_folder; +@@ -138,7 +142,7 @@ + flags:(NSArray *)_flags; + - (NSDictionary *)storeFrom:(unsigned)_from to:(unsigned)_to + add:(NSNumber *)_add flags:(NSArray *)_flags; +-- (NSDictionary *)storeFlags:(NSArray *)_flags forMSNs:(id)_msns ++- (NSDictionary *)storeFlags:(NSArray *)_flags forUIDs:(id)_uids + addOrRemove:(BOOL)_flag; + + - (NSDictionary *)copyUid:(unsigned)_uid toFolder:(NSString *)_folder; +Index: sope-mime/NGImap4/NGImap4Client.m +=================================================================== +--- sope-mime/NGImap4/NGImap4Client.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4Client.m (working copy) +@@ -24,6 +24,8 @@ + #include "NGImap4Client.h" + #include "NGImap4Context.h" + #include "NGImap4Support.h" ++#include "NGImap4Envelope.h" ++#include "NGImap4EnvelopeAddress.h" + #include "NGImap4Functions.h" + #include "NGImap4ResponseParser.h" + #include "NGImap4ResponseNormalizer.h" +@@ -53,17 +55,17 @@ + + @end /* NGImap4Client(ConnectionRegistration); */ + +-#if GNUSTEP_BASE_LIBRARY +-/* FIXME: TODO: move someplace better (hh: NGExtensions...) */ +-@implementation NSException(setUserInfo) ++// #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; +-} ++// - (id)setUserInfo:(NSDictionary *)_userInfo { ++// ASSIGN(self->_e_info, _userInfo); ++// return self; ++// } + +-@end /* NSException(setUserInfo) */ +-#endif ++// @end /* NSException(setUserInfo) */ ++// #endif + + @interface NGImap4Client(Private) + +@@ -84,6 +86,8 @@ + + - (NSDictionary *)login; + ++- (NSDictionary *) _sopeSORT: (id)_sortSpec qualifier:(EOQualifier *)_qual encoding:(NSString *)_encoding; ++ + @end + + /* +@@ -110,6 +114,9 @@ + static BOOL ImapDebugEnabled = NO; + static NSArray *Imap4SystemFlags = nil; + ++static NSMutableDictionary *capabilities; ++static NSMutableDictionary *namespaces; ++ + - (BOOL)useSSL { + return self->useSSL; + } +@@ -140,6 +147,9 @@ + + Imap4SystemFlags = [[NSArray alloc] initWithObjects: @"seen", @"answered", + @"deleted", @"draft", nil]; ++ ++ capabilities = [[NSMutableDictionary alloc] init]; ++ namespaces = [[NSMutableDictionary alloc] init]; + } + + /* constructors */ +@@ -195,11 +205,14 @@ + self->debug = ImapDebugEnabled; + self->responseReceiver = [[NSMutableArray alloc] initWithCapacity:128]; + self->normer = [[NGImap4ResponseNormalizer alloc] initWithClient:self]; ++ self->loggedIn = NO; ++ self->context = nil; + } + return self; + } + + - (void)dealloc { ++ if (self->loggedIn) [self logout]; + [self removeFromConnectionRegister]; + [self->normer release]; + [self->text release]; +@@ -457,8 +470,8 @@ + - (void)reconnect { + if ([self->context lastException] != nil) + return; +- +- [self closeConnection]; ++ ++ [self closeConnection]; + self->tagId = 0; + [self openConnection]; + +@@ -481,6 +494,7 @@ + */ + NGHashMap *map; + NSString *s, *log; ++ NSDictionary *response; + + if (self->isLogin ) + return nil; +@@ -499,7 +513,11 @@ + + self->isLogin = NO; + +- return [self->normer normalizeResponse:map]; ++ response = [self->normer normalizeResponse:map]; ++ ++ self->loggedIn = [[response valueForKey:@"result"] boolValue]; ++ ++ return response; + } + + - (NSDictionary *)logout { +@@ -508,6 +526,8 @@ + + map = [self processCommand:@"logout"]; + [self closeConnection]; ++ [self->selectedFolder release]; self->selectedFolder = nil; ++ self->loggedIn = NO; + + return [self->normer normalizeResponse:map]; + } +@@ -530,7 +550,7 @@ + NSAutoreleasePool *pool; + NGHashMap *map; + NSDictionary *result; +- NSString *s; ++ NSString *s, *prefix; + + pool = [[NSAutoreleasePool alloc] init]; + +@@ -547,7 +567,11 @@ + if (!(_pattern = [self _folder2ImapFolder:_pattern])) + return nil; + +- s = [NSString stringWithFormat:@"list \"%@\" \"%@\"", _folder, _pattern]; ++ if ([_folder length] > 0) ++ prefix = [NSString stringWithFormat: @"%@%@", SaneFolderName(_folder), self->delimiter]; ++ else ++ prefix = @""; ++ s = [NSString stringWithFormat:@"list \"%@\" \"%@\"", prefix, _pattern]; + map = [self processCommand:s]; + + if (self->delimiter == nil) { +@@ -563,18 +587,49 @@ + } + + - (NSDictionary *)capability { ++ NSDictionary *result; + id capres; +- capres = [self processCommand:@"capability"]; +- return [self->normer normalizeCapabilityRespone:capres]; ++ ++ result = [capabilities objectForKey: [self->address description]]; ++ ++ if (!result) ++ { ++ capres = [self processCommand:@"capability"]; ++ result = [self->normer normalizeCapabilityResponse:capres]; ++ ++ if (result) ++ [capabilities setObject: result forKey: [self->address description]]; ++ } ++ return result; + } + ++- (NSDictionary *)namespace { ++ NSArray *capabilities; ++ NGHashMap *namesres; ++ id namespace; ++ ++ namespace = [namespaces objectForKey: [self->address description]]; ++ if (!namespace) { ++ capabilities = [[self capability] objectForKey: @"capability"]; ++ if ([capabilities containsObject: @"namespace"]) { ++ namesres = [self processCommand: @"namespace"]; ++ namespace = [self->normer normalizeNamespaceResponse:namesres]; ++ } ++ else ++ namespace = [NSNull null]; ++ [namespaces setObject: namespace forKey: [self->address description]]; ++ } ++ ++ return ([namespace isKindOfClass: [NSNull class]] ? nil : namespace); ++} ++ + - (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; ++ NSString *s, *prefix; + + if (_folder == nil) + _folder = @""; +@@ -591,7 +646,11 @@ + return nil; + } + +- s = [NSString stringWithFormat:@"lsub \"%@\" \"%@\"", _folder, _pattern]; ++ if ([_folder length] > 0) ++ prefix = [NSString stringWithFormat: @"%@%@", SaneFolderName(_folder), self->delimiter]; ++ else ++ prefix = @""; ++ s = [NSString stringWithFormat:@"lsub \"%@\" \"%@\"", prefix, _pattern]; + map = [self processCommand:s]; + + if (self->delimiter == nil) { +@@ -617,24 +676,25 @@ + 'flags' - array of strings (eg (answered,flagged,draft,seen); + 'RawResponse' - the raw IMAP4 response + */ +- NSString *s; +- id tmp; +- +- tmp = self->selectedFolder; // remember ptr to old folder name +- ++ NSString *s, *newFolder; ++ + if (![_folder isNotEmpty]) + return nil; + if ((_folder = [self _folder2ImapFolder:_folder]) == nil) + return nil; + +- self->selectedFolder = [_folder copy]; +- +- [tmp release]; tmp = nil; // release old folder name ++ newFolder = [NSString stringWithString: _folder]; ++ ASSIGN (self->selectedFolder, newFolder); + +- s = [NSString stringWithFormat:@"select \"%@\"", self->selectedFolder]; ++ s = [NSString stringWithFormat:@"select \"%@\"", SaneFolderName(self->selectedFolder)]; + return [self->normer normalizeSelectResponse:[self processCommand:s]]; + } + ++- (NSDictionary *)unselect { ++ [self->selectedFolder release]; self->selectedFolder = nil; ++ return [self->normer normalizeResponse:[self processCommand:@"unselect"]]; ++} ++ + - (NSDictionary *)status:(NSString *)_folder flags:(NSArray *)_flags { + NSString *cmd; + +@@ -646,7 +706,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"status \"%@\" (%@)", +- _folder, [_flags componentsJoinedByString:@" "]]; ++ SaneFolderName(_folder), [_flags componentsJoinedByString:@" "]]; + return [self->normer normalizeStatusResponse:[self processCommand:cmd]]; + } + +@@ -663,24 +723,28 @@ + if ((_newName = [self _folder2ImapFolder:_newName]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"rename \"%@\" \"%@\"", _folder, _newName]; ++ cmd = [NSString stringWithFormat:@"rename \"%@\" \"%@\"", ++ SaneFolderName(_folder), SaneFolderName(_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]; +- ++ command = [NSString stringWithFormat:@"%@ \"%@\"", _op, SaneFolderName(_fname)]; ++ + return [self->normer normalizeResponse:[self processCommand:command]]; + } + + - (NSDictionary *)delete:(NSString *)_name { ++ if ([self->selectedFolder isEqualToString:_name]) { ++ [self unselect]; ++ } + return [self _performCommand:@"delete" onFolder:_name]; + } + - (NSDictionary *)create:(NSString *)_name { +@@ -820,23 +884,23 @@ + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + +-- (NSDictionary *)storeFlags:(NSArray *)_flags forMSNs:(id)_msns ++- (NSDictionary *)storeFlags:(NSArray *)_flags forUIDs:(id)_uids + addOrRemove:(BOOL)_flag + { + NSString *cmd; + NSString *flagstr; + NSString *seqstr; + +- if ([_msns isKindOfClass:[NSArray class]]) { ++ if ([_uids isKindOfClass:[NSArray class]]) { + // TODO: improve by using ranges, eg 1:5 instead of 1,2,3,4,5 +- _msns = [_msns valueForKey:@"stringValue"]; +- seqstr = [_msns componentsJoinedByString:@","]; ++ _uids = [_uids valueForKey:@"stringValue"]; ++ seqstr = [_uids componentsJoinedByString:@","]; + } + else +- seqstr = [_msns stringValue]; ++ seqstr = [_uids stringValue]; + + flagstr = [_flags2ImapFlags(self, _flags) componentsJoinedByString:@" "]; +- cmd = [NSString stringWithFormat:@"store %@ %cFLAGS (%@)", ++ cmd = [NSString stringWithFormat:@"UID STORE %@ %cFLAGS (%@)", + seqstr, _flag ? '+' : '-', flagstr]; + + return [self->normer normalizeResponse:[self processCommand:cmd]]; +@@ -967,11 +1031,12 @@ + 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]; ++ exception ++ = [NGImap4SearchException exceptionWithName: @"NGImap4SearchException" ++ reason: descr ++ userInfo: ui]; + [self->context setLastException:exception]; +- [exception release]; + } + + - (NSString *)_searchExprForQual:(EOQualifier *)_qualifier { +@@ -1093,7 +1158,18 @@ + Eg: UID SORT ( DATE REVERSE SUBJECT ) UTF-8 TODO + */ + NSString *tmp; ++ NSArray *capa; + ++ // We first check to see if our server supports IMAP SORT. If not ++ // we'll sort ourself the results. ++ capa = [[self capability] objectForKey: @"capability"]; ++ ++ if ([capa indexOfObject: @"sort"] == NSNotFound) ++ { ++ return [self _sopeSORT: _sortSpec qualifier: _qual encoding: _encoding]; ++ } ++ ++ + if ([_sortSpec isKindOfClass:[NSArray class]]) + tmp = [self _generateIMAP4SortOrderings:_sortSpec]; + else if ([_sortSpec isKindOfClass:[EOSortOrdering class]]) +@@ -1107,9 +1183,10 @@ + tmp = @"DATE"; + } + ++ + return [self primarySort:tmp +- qualifierString:[self _searchExprForQual:_qual] +- encoding:_encoding]; ++ qualifierString:[self _searchExprForQual:_qual] ++ encoding:_encoding]; + } + - (NSDictionary *)sort:(NSArray *)_sortOrderings + qualifier:(EOQualifier *)_qual +@@ -1130,7 +1207,7 @@ + return nil; + } + +- s = [@"search" stringByAppendingString:s]; ++ s = [@"UID SEARCH" stringByAppendingString:s]; + return [self->normer normalizeSearchResponse:[self processCommand:s]]; + } + +@@ -1142,7 +1219,7 @@ + if ((_folder = [self _folder2ImapFolder:_folder]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"getacl \"%@\"", _folder]; ++ cmd = [NSString stringWithFormat:@"getacl \"%@\"", SaneFolderName(_folder)]; + return [self->normer normalizeGetACLResponse:[self processCommand:cmd]]; + } + +@@ -1155,7 +1232,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"setacl \"%@\" \"%@\" \"%@\"", +- _folder, _uid, _r]; ++ SaneFolderName(_folder), _uid, _r]; + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + +@@ -1166,7 +1243,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"deleteacl \"%@\" \"%@\"", +- _folder, _uid]; ++ SaneFolderName(_folder), _uid]; + return [self->normer normalizeResponse:[self processCommand:cmd]]; + } + +@@ -1177,7 +1254,7 @@ + return nil; + + cmd = [NSString stringWithFormat:@"listrights \"%@\" \"%@\"", +- _folder, _uid]; ++ SaneFolderName(_folder), _uid]; + return [self->normer normalizeListRightsResponse:[self processCommand:cmd]]; + } + +@@ -1187,12 +1264,94 @@ + if ((_folder = [self _folder2ImapFolder:_folder]) == nil) + return nil; + +- cmd = [NSString stringWithFormat:@"myrights \"%@\"", _folder]; ++ cmd = [NSString stringWithFormat:@"myrights \"%@\"", SaneFolderName(_folder)]; + return [self->normer normalizeMyRightsResponse:[self processCommand:cmd]]; + } + + /* Private Methods */ + ++- (NSDictionary *) _sopeSORT: (id)_sortSpec qualifier:(EOQualifier *)_qual encoding:(NSString *)_encoding { ++ NSMutableDictionary *result; ++ NSDictionary *d; ++ NSCalendarDate *envDate; ++ ++ result = [NSMutableDictionary dictionary]; ++ [result setObject: [NSNumber numberWithBool: NO] forKey: @"result"]; ++ ++ // _sortSpec: [REVERSE] {DATE,FROM,SUBJECT} ++ d = [self searchWithQualifier: _qual]; ++ ++ if ((d = [d objectForKey: @"RawResponse"])) { ++ NSMutableDictionary *dict; ++ NSArray *a, *s_a; ++ BOOL b; ++ int i; ++ ++ a = [d objectForKey: @"search"]; ++ if ([a isNotEmpty]) { ++ d = [self fetchUids: a ++ parts: [NSArray arrayWithObjects: @"ENVELOPE", ++ @"RFC822.SIZE", nil]]; ++ a = [d objectForKey: @"fetch"]; ++ ++ dict = [NSMutableDictionary dictionary]; ++ b = YES; ++ ++ for (i = 0; i < [a count]; i++) { ++ NGImap4Envelope *env; ++ id o, uid, s; ++ ++ o = [a objectAtIndex: i]; ++ env = [o objectForKey: @"envelope"]; ++ uid = [o objectForKey: @"uid"]; ++ ++ if ([_sortSpec rangeOfString: @"SUBJECT"].length) { ++ s = [env subject]; ++ if ([s isKindOfClass: [NSData class]]) ++ s = [[[NSString alloc] initWithData: s encoding: NSUTF8StringEncoding] autorelease]; ++ ++ [dict setObject: (s != nil ? s : (id)@"") forKey: uid]; ++ } ++ else if ([_sortSpec rangeOfString: @"FROM"].length) { ++ s = [[[env from] lastObject] email]; ++ [dict setObject: (s != nil ? s : (id)@"") forKey: uid]; ++ } ++ else if ([_sortSpec rangeOfString: @"SIZE"].length) { ++ s = [o objectForKey: @"size"]; ++ [dict setObject: (s != nil ? s : [NSNumber numberWithInt: 0]) ++ forKey: uid]; ++ b = NO; ++ } ++ else { ++ envDate = [env date]; ++ if (!envDate) ++ envDate = [NSCalendarDate date]; ++ [dict setObject: envDate forKey: uid]; ++ b = NO; ++ } ++ } ++ ++ if (b) ++ s_a = [dict keysSortedByValueUsingSelector: @selector(caseInsensitiveCompare:)]; ++ else ++ s_a = [dict keysSortedByValueUsingSelector: @selector(compare:)]; ++ ++ if ([_sortSpec rangeOfString: @"REVERSE"].length) { ++ s_a = [[s_a reverseObjectEnumerator] allObjects]; ++ } ++ ++ } ++ else { ++ s_a = [NSArray array]; ++ } ++ [result setObject: [NSNumber numberWithBool: YES] forKey: @"result"]; ++ [result setObject: s_a forKey: @"sort"]; ++ } ++ ++ return result; ++} ++ ++ + - (NSException *)_processCommandParserException:(NSException *)_exception { + [self logWithFormat:@"ERROR(%s): catched IMAP4 parser exception %@: %@", + __PRETTY_FUNCTION__, [_exception name], [_exception reason]]; +@@ -1412,21 +1571,24 @@ + return nil; + } + +- array = [_folder pathComponents]; ++// array = [_folder pathComponents]; ++ array = [_folder componentsSeparatedByString:@"/"]; + +- if ([array isNotEmpty]) { ++ if ([array count]) { + NSString *o; + + o = [array objectAtIndex:0]; +- if (([o isEqualToString:@"/"]) || ([o length] == 0)) ++ if ([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)]; ++ ++ if ([array count]) { ++ o = [array lastObject]; ++ if ([o length] == 0) ++ array = [array subarrayWithRange:NSMakeRange(0, [array count] - 1)]; ++ } + } + return [[array componentsJoinedByString:self->delimiter] +- stringByEncodingImap4FolderName]; ++ stringByEncodingImap4FolderName]; + } + + - (NSString *)_imapFolder2Folder:(NSString *)_folder { +@@ -1442,10 +1604,16 @@ + return nil; + } + ++ if ([_folder hasPrefix: self->delimiter]) ++ _folder = [_folder substringFromIndex: 1]; ++ if ([_folder hasSuffix: self->delimiter]) ++ _folder = [_folder substringToIndex: [_folder length] - 1]; ++ + array = [array arrayByAddingObjectsFromArray: + [_folder componentsSeparatedByString:[self delimiter]]]; +- +- return [[NSString pathWithComponents:array] stringByDecodingImap4FolderName]; ++ ++ return [[array componentsJoinedByString: @"/"] ++ stringByDecodingImap4FolderName]; + } + + - (void)setContext:(NGImap4Context *)_ctx { +Index: sope-mime/NGImap4/NGSieveClient.m +=================================================================== +--- sope-mime/NGImap4/NGSieveClient.m (revision 1664) ++++ sope-mime/NGImap4/NGSieveClient.m (working copy) +@@ -294,8 +294,8 @@ + return con; + } + +- logLen = [self->login cStringLength]; +- bufLen = (logLen * 2) + [self->password cStringLength] +2; ++ logLen = [self->login lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; ++ bufLen = (logLen * 2) + [self->password lengthOfBytesUsingEncoding: NSUTF8StringEncoding] +2; + + buf = calloc(bufLen + 2, sizeof(char)); + +@@ -306,8 +306,9 @@ + password + */ + sprintf(buf, "%s %s %s", +- [self->login cString], [self->login cString], +- [self->password cString]); ++ [self->login cStringUsingEncoding:NSUTF8StringEncoding], ++ [self->login cStringUsingEncoding:NSUTF8StringEncoding], ++ [self->password cStringUsingEncoding:NSUTF8StringEncoding]); + + buf[logLen] = '\0'; + buf[logLen * 2 + 1] = '\0'; +@@ -656,7 +657,7 @@ + fputc('\n', stderr); + } + else +- fprintf(stderr, "C: %s\n", [_txt cString]); ++ fprintf(stderr, "C: %s\n", [_txt cStringUsingEncoding:NSUTF8StringEncoding]); + } + + /* write */ +Index: sope-mime/NGImap4/NGImap4Connection.h +=================================================================== +--- sope-mime/NGImap4/NGImap4Connection.h (revision 1664) ++++ sope-mime/NGImap4/NGImap4Connection.h (working copy) +@@ -52,7 +52,7 @@ + NSString *separator; + + /* hierarchy cache */ +- NSDictionary *subfolders; ++ NSMutableDictionary *subfolders; + + /* permission cache */ + NSMutableDictionary *urlToRights; +@@ -72,8 +72,9 @@ + + - (NSDate *)creationTime; + +-- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy; +-- (NSDictionary *)cachedHierarchyResults; ++- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy ++ forURL:(NSURL *)_url; ++- (NSDictionary *)cachedHierarchyResultsForURL:(NSURL *)_url; + - (void)flushFolderHierarchyCache; + + - (id)cachedUIDsForURL:(NSURL *)_url qualifier:(id)_q sortOrdering:(id)_so; +@@ -88,7 +89,12 @@ + /* folder operations */ + + - (NSArray *)subfoldersForURL:(NSURL *)_url; ++- (NSArray *)subfoldersForURL:(NSURL *)_url ++ onlySubscribedFolders: (BOOL) subscribedFoldersOnly; + - (NSArray *)allFoldersForURL:(NSURL *)_url; ++- (NSArray *)allFoldersForURL:(NSURL *)_url ++ onlySubscribedFolders: (BOOL) subscribedFoldersOnly; ++- (BOOL)selectFolder:(id)_url; + + /* message operations */ + +Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.h +=================================================================== +--- sope-mime/NGImap4/NGImap4ResponseNormalizer.h (revision 1664) ++++ sope-mime/NGImap4/NGImap4ResponseNormalizer.h (working copy) +@@ -49,7 +49,8 @@ + - (NSDictionary *)normalizeSearchResponse:(NGHashMap *)_map; + - (NSDictionary *)normalizeSortResponse:(NGHashMap *)_map; + - (NSDictionary *)normalizeThreadResponse:(NGHashMap *)_map; +-- (NSDictionary *)normalizeCapabilityRespone:(NGHashMap *)_map; ++- (NSDictionary *)normalizeCapabilityResponse:(NGHashMap *)_map; ++- (NSDictionary *)normalizeNamespaceResponse:(NGHashMap *)_map; + - (NSDictionary *)normalizeQuotaResponse:(NGHashMap *)_map; + + /* ACL */ +Index: sope-mime/NGImap4/NGImap4Connection.m +=================================================================== +--- sope-mime/NGImap4/NGImap4Connection.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4Connection.m (working copy) +@@ -22,6 +22,7 @@ + #include "NGImap4Connection.h" + #include "NGImap4MailboxInfo.h" + #include "NGImap4Client.h" ++#include "NGImap4Functions.h" + #include "imCommon.h" + + @implementation NGImap4Connection +@@ -66,7 +67,8 @@ + self->creationTime = [[NSDate alloc] init]; + + // TODO: retrieve from IMAP4 instead of using a default +- self->separator = imap4Separator; ++ self->separator = [imap4Separator copy]; ++ self->subfolders = [NSMutableDictionary new]; + } + return self; + } +@@ -100,11 +102,13 @@ + return self->creationTime; + } + +-- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy { +- ASSIGNCOPY(self->subfolders, _hierarchy); ++- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy ++ forURL:(NSURL *)_url ++{ ++ [self->subfolders setObject:_hierarchy forKey:[_url absoluteString]]; + } +-- (NSDictionary *)cachedHierarchyResults { +- return self->subfolders; ++- (NSDictionary *)cachedHierarchyResultsForURL:(NSURL *)_url { ++ return [self->subfolders objectForKey:[_url absoluteString]]; + } + - (void)flushFolderHierarchyCache { + [self->subfolders release]; self->subfolders = nil; +@@ -152,7 +156,6 @@ + ASSIGN(self->cachedUIDs, nil); + } + +- + /* errors */ + + - (NSException *)errorCouldNotSelectURL:(NSURL *)_url { +@@ -215,18 +218,13 @@ + NSMutableArray *ma; + unsigned i, count, prefixlen; + +- if ((count = [_array count]) < 2) { +- /* one entry is the folder itself, so we need at least two */ +- return [NSArray array]; +- } ++ count = [_array count]; + + // TODO: somehow results are different on OSX + // we should investigate and test all Foundation libraries and document the + // differences + #if __APPLE__ + prefixlen = [_fn isEqualToString:@""] ? 0 : [_fn length] + 1; +-#elif GNUSTEP_BASE_LIBRARY +- prefixlen = [_fn isEqualToString:@"/"] ? 1 : [_fn length]; + #else + prefixlen = [_fn isEqualToString:@"/"] ? 1 : [_fn length] + 1; + #endif +@@ -321,13 +319,15 @@ + return nil; + if ([folderName characterAtIndex:0] == '/') + folderName = [folderName substringFromIndex:1]; ++ if ([folderName hasSuffix: @"/"]) ++ folderName = [folderName substringToIndex:[folderName length] - 1]; + + if (_delfn) folderName = [folderName stringByDeletingLastPathComponent]; + + if ([[self imap4Separator] isEqualToString:@"/"]) + return folderName; + +- names = [folderName pathComponents]; ++ names = [folderName componentsSeparatedByString: @"/"]; + return [names componentsJoinedByString:[self imap4Separator]]; + } + - (NSString *)imap4FolderNameForURL:(NSURL *)_url { +@@ -373,16 +373,26 @@ + + /* folder operations */ + +-- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url { ++- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url ++ onlySubscribedFolders:(BOOL) subscribedFoldersOnly ++{ + NSDictionary *result; ++ NSString *prefix; + +- if ((result = [self cachedHierarchyResults]) != nil) ++ if ((result = [self cachedHierarchyResultsForURL:_url]) != nil) + return [result isNotNull] ? result : (NSDictionary *)nil; + + if (debugCache) [self logWithFormat:@" no folders cached yet .."]; +- +- result = [[self client] list:(onlyFetchInbox ? @"INBOX" : @"*") +- pattern:@"*"]; ++ ++ prefix = [_url path]; ++ if ([prefix hasPrefix: @"/"]) ++ prefix = [prefix substringFromIndex:1]; ++ if (subscribedFoldersOnly) ++ result = [[self client] lsub:(onlyFetchInbox ? @"INBOX" : prefix) ++ pattern:@"*"]; ++ else ++ result = [[self client] list:(onlyFetchInbox ? @"INBOX" : prefix) ++ pattern:@"*"]; + if (![[result valueForKey:@"result"] boolValue]) { + [self errorWithFormat:@"Could not list mailbox hierarchy!"]; + return nil; +@@ -391,7 +401,7 @@ + /* cache results */ + + if ([result isNotNull]) { +- [self cacheHierarchyResults:result]; ++ [self cacheHierarchyResults:result forURL:_url]; + if (debugCache) { + [self logWithFormat:@"cached results: 0x%p(%d)", + result, [result count]]; +@@ -400,32 +410,55 @@ + return result; + } + +-- (NSArray *)subfoldersForURL:(NSURL *)_url { ++- (NSDictionary *)primaryFetchMailboxHierarchyForURL:(NSURL *)_url ++{ ++ return [self primaryFetchMailboxHierarchyForURL: _url onlySubscribedFolders: NO]; ++} ++ ++- (NSArray *)allFoldersForURL:(NSURL *)_url ++ onlySubscribedFolders:(BOOL)_subscribedFoldersOnly ++{ + NSDictionary *result; + +- if ((result = [self primaryFetchMailboxHierarchyForURL:_url]) == nil) ++ if ((result = [self primaryFetchMailboxHierarchyForURL:_url ++ onlySubscribedFolders:_subscribedFoldersOnly]) == nil) + return nil; + if ([result isKindOfClass:[NSException class]]) { + [self errorWithFormat:@"failed to retrieve hierarchy: %@", result]; + return nil; + } + +- return [self extractSubfoldersForURL:_url fromResultSet:result]; ++ return [self extractFoldersFromResultSet:result]; + } + +-- (NSArray *)allFoldersForURL:(NSURL *)_url { ++- (NSArray *)allFoldersForURL:(NSURL *)_url ++{ ++ return [self allFoldersForURL: _url onlySubscribedFolders: NO]; ++} ++ ++- (NSArray *)subfoldersForURL:(NSURL *)_url ++ onlySubscribedFolders:(BOOL)_subscribedFoldersOnly ++{ + NSDictionary *result; ++ NSString *baseFolder; + +- if ((result = [self primaryFetchMailboxHierarchyForURL:_url]) == nil) ++ baseFolder = [self imap4FolderNameForURL:_url removeFileName:NO]; ++ if (_subscribedFoldersOnly) ++ result = [[self client] lsub:baseFolder pattern:@"%"]; ++ else ++ result = [[self client] list:baseFolder pattern:@"%"]; ++ if (![[result valueForKey:@"result"] boolValue]) { ++ [self errorWithFormat:@"Could not list mailbox hierarchy!"]; + return nil; +- if ([result isKindOfClass:[NSException class]]) { +- [self errorWithFormat:@"failed to retrieve hierarchy: %@", result]; +- return nil; + } +- +- return [self extractFoldersFromResultSet:result]; ++ ++ return [self extractSubfoldersForURL:_url fromResultSet: result]; + } + ++- (NSArray *)subfoldersForURL:(NSURL *)_url { ++ return [self subfoldersForURL:_url onlySubscribedFolders: NO]; ++} ++ + /* message operations */ + + - (NSArray *)fetchUIDsInURL:(NSURL *)_url qualifier:(id)_qualifier +@@ -646,7 +679,7 @@ + + /* store flags */ + +- result = [[self client] storeFlags:_f forMSNs:result addOrRemove:YES]; ++ result = [[self client] storeFlags:_f forUIDs:result addOrRemove:YES]; + if (![[result valueForKey:@"result"] boolValue]) { + return [self errorForResult:result + text:@"Failed to change flags of IMAP4 message"]; +@@ -737,14 +770,17 @@ + + - (BOOL)doesMailboxExistAtURL:(NSURL *)_url { + NSString *folderName; ++ NSArray *caches; + id result; ++ int count, max; + + /* check in hierarchy cache */ +- +- if ((result = [self cachedHierarchyResults]) != nil) { ++ caches = [self->subfolders allValues]; ++ max = [caches count]; ++ for (count = 0; count < max; count++) { + NSString *p; +- +- result = [(NSDictionary *)result objectForKey:@"list"]; ++ ++ result = [[caches objectAtIndex: count] objectForKey:@"list"]; + p = [_url path]; + #if __APPLE__ + /* normalized results already have the / in front on libFoundation?! */ +@@ -760,11 +796,11 @@ + // TODO: we should probably just fetch the whole hierarchy? + + folderName = [self imap4FolderNameForURL:_url]; +- result = [[self client] select:folderName]; +- if (![[result valueForKey:@"result"] boolValue]) +- return NO; +- +- return YES; ++ ++ result = [self->client status: folderName ++ flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]; ++ ++ return ([[result valueForKey: @"result"] boolValue]); + } + + - (id)infoForMailboxAtURL:(NSURL *)_url { +@@ -789,7 +825,8 @@ + /* construct path */ + + newPath = [self imap4FolderNameForURL:_url]; +- newPath = [newPath stringByAppendingString:[self imap4Separator]]; ++ if ([newPath length]) ++ newPath = [newPath stringByAppendingString:[self imap4Separator]]; + newPath = [newPath stringByAppendingString:_mailbox]; + + /* create */ +Index: sope-mime/NGImap4/NGImap4ResponseNormalizer.m +=================================================================== +--- sope-mime/NGImap4/NGImap4ResponseNormalizer.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4ResponseNormalizer.m (working copy) +@@ -76,22 +76,6 @@ + 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 { +@@ -117,7 +101,7 @@ + if ((obj = [_map objectForKey:@"bye"])) { + [result setObject:NoNumber forKey:@"result"]; + [result setObject:obj forKey:@"reason"]; +- [self closeConnection]; ++ [self->client closeConnection]; + return result; + } + +@@ -157,7 +141,7 @@ + return result; + } + +-- (NSDictionary *)normalizeCapabilityRespone:(NGHashMap *)_map { ++- (NSDictionary *)normalizeCapabilityResponse:(NGHashMap *)_map { + /* filter for capability response: capability : NSArray */ + id obj; + NSMutableDictionary *result; +@@ -170,6 +154,51 @@ + return result; + } + ++- (NSArray *)_normalizeNamespace:(NSArray *)_namespace { ++ NSMutableArray *result; ++ NSDictionary *currentNS; ++ NSMutableDictionary *newNS; ++ NSString *newPrefix; ++ int count, max; ++ ++ max = [_namespace count]; ++ result = [NSMutableArray arrayWithCapacity: max]; ++ for (count = 0; count < max; count++) { ++ currentNS = [_namespace objectAtIndex: count]; ++ newNS = [currentNS mutableCopy]; ++ newPrefix = [self->client ++ _imapFolder2Folder: [currentNS objectForKey: @"prefix"]]; ++ [newNS setObject: newPrefix forKey: @"prefix"]; ++ [result addObject: newNS]; ++ [newNS release]; ++ } ++ ++ return result; ++} ++ ++- (NSDictionary *)normalizeNamespaceResponse:(NGHashMap *)_map { ++ NSMutableDictionary *result; ++ NSDictionary *rawResponse; ++ NSArray *namespace; ++ ++ result = [self normalizeResponse:_map]; ++ rawResponse = [result objectForKey: @"RawResponse"]; ++ namespace = [rawResponse objectForKey: @"personal"]; ++ if (namespace) ++ [result setObject: [self _normalizeNamespace: namespace] ++ forKey: @"personal"]; ++ namespace = [rawResponse objectForKey: @"other users"]; ++ if (namespace) ++ [result setObject: [self _normalizeNamespace: namespace] ++ forKey: @"other users"]; ++ namespace = [rawResponse objectForKey: @"shared"]; ++ if (namespace) ++ [result setObject: [self _normalizeNamespace: namespace] ++ forKey: @"shared"]; ++ ++ return result; ++} ++ + - (NSDictionary *)normalizeThreadResponse:(NGHashMap *)_map { + /* filter for thread response: thread : NSArray (msn) */ + id obj; +@@ -292,7 +321,7 @@ + /* + filter for fetch response + fetch : NSArray (fetch responses) +- 'header' - RFC822.HEADER ++ 'header' - RFC822.HEADER and BODY[HEADER.FIELDS (...)] + 'text' - RFC822.TEXT + 'size' - SIZE + 'flags' - FLAGS +@@ -336,7 +365,12 @@ + switch (c) { + case 'b': + /* Note: we check for _prefix_! eg body[1] is valid too */ +- if (klen > 3 && [key hasPrefix:@"body"]) { ++ if (klen > 17 && [key hasPrefix:@"body[header.fields"]) { ++ keys[count] = @"header"; ++ values[count] = objForKey(obj, @selector(objectForKey:), key); ++ count++; ++ } ++ else if (klen > 3 && [key hasPrefix:@"body"]) { + keys[count] = @"body"; + values[count] = objForKey(obj, @selector(objectForKey:), key); + count++; +@@ -516,7 +550,7 @@ + } + continue; + } +- [tmp setObject:qDesc forKey:[self _imapFolder2Folder:obj]]; ++ [tmp setObject:qDesc forKey:[self->client _imapFolder2Folder:obj]]; + } + [result setObject:tmp forKey:@"quotas"]; + return [[result copy] autorelease]; +@@ -615,7 +649,7 @@ + + while ((o = [enumerator nextObject])) { + [folder setObject:_imapFlags2Flags(self, [o objectForKey:@"flags"]) +- forKey:[self _imapFolder2Folder:[o objectForKey:@"folderName"]]]; ++ forKey:[self->client _imapFolder2Folder:[o objectForKey:@"folderName"]]]; + } + + { +@@ -648,14 +682,13 @@ + enumerator = [_flags objectEnumerator]; + cnt = 0; + while ((obj = [enumerator nextObject])) { +- if (![obj isNotEmpty]) +- continue; +- +- if (![[obj substringToIndex:1] isEqualToString:@"\\"]) +- continue; +- +- objs[cnt] = [obj substringFromIndex:1]; +- cnt++; ++ if ([obj isNotEmpty]) { ++ if ([obj hasPrefix:@"\\"]) ++ objs[cnt] = [obj substringFromIndex:1]; ++ else ++ objs[cnt] = obj; ++ cnt++; ++ } + } + result = [NSArray arrayWithObjects:objs count:cnt]; + if (objs) free(objs); +Index: sope-mime/NGImap4/EOQualifier+IMAPAdditions.m +=================================================================== +--- sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (revision 1664) ++++ sope-mime/NGImap4/EOQualifier+IMAPAdditions.m (working copy) +@@ -53,13 +53,13 @@ + 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]; ++ FlagKeyWords = [[NSArray alloc] initWithObjects: @"ANSWERED", @"DELETED", ++ @"DRAFT", @"FLAGGED", @"NEW", @"OLD", @"RECENT", ++ @"SEEN", @"UNANSWERED", @"UNDELETED", @"UNDRAFT", ++ @"UNFLAGGED", @"UNSEEN", nil]; ++ OtherKeyWords = [[NSArray alloc] initWithObjects: @"ALL", @"BCC", @"BODY", ++ @"CC", @"FROM", @"SUBJECT", @"TEXT", @"TO", ++ @"KEYWORD", @"UID", @"UNKEYWORD", nil]; + + debugOn = [ud boolForKey:@"ImapDebugQualifierGeneration"]; + } +@@ -266,10 +266,10 @@ + + enumerator = [lvalue objectEnumerator]; + while ((lvalue = [enumerator nextObject]) != nil) { +- lvalue = [lvalue lowercaseString]; ++ lvalue = [lvalue uppercaseString]; + + if ([FlagKeyWords containsObject:lvalue]) { +- if (insertNot) [search appendString:@"not "]; ++ if (insertNot) [search appendString:@"NOT "]; + [search appendString:lvalue]; + } + else { +@@ -280,15 +280,31 @@ + return nil; + } + +-- (NSString *)imap4OperatorForDateComparisonSelector:(SEL)lselector { ++- (NSString *)imap4OperatorForDateKeyword:(NSString *)dkey ++andComparisonSelector:(SEL)lselector { ++ NSString *operatorPrefix, *dateOperator, *imap4Operator; ++ + if (sel_eq(lselector, EOQualifierOperatorEqual)) +- return @" senton "; +- if (sel_eq(lselector, EOQualifierOperatorGreaterThan)) +- return @" sentsince "; +- if (sel_eq(lselector, EOQualifierOperatorLessThan)) +- return @" sentbefore "; +- +- return nil; ++ dateOperator = @"ON"; ++ else if (sel_eq(lselector, EOQualifierOperatorGreaterThan)) ++ dateOperator = @"SINCE"; ++ else if (sel_eq(lselector, EOQualifierOperatorLessThan)) ++ dateOperator = @"BEFORE"; ++ else ++ dateOperator = nil; ++ ++ if (dateOperator) { ++ if ([dkey isEqualToString: @"DATE"]) ++ operatorPrefix = @"SENT"; ++ else ++ operatorPrefix = @""; ++ imap4Operator = [NSString stringWithFormat: @"%@%@ ", ++ operatorPrefix, dateOperator]; ++ } ++ else ++ imap4Operator = nil; ++ ++ return imap4Operator; + } + + - (NSException *)appendToImap4SearchString:(NSMutableString *)search +@@ -300,11 +316,11 @@ + id lvalue; + SEL lselector; + +- lkey = [[self key] lowercaseString]; ++ lkey = [[self key] uppercaseString]; + lvalue = [self value]; + lselector = [self selector]; + +- if ([lkey isEqualToString:@"flags"]) { ++ if ([lkey isEqualToString:@"FLAGS"]) { + /* NOTE: special "not" processing! */ + return [self appendFlagsCheckToImap4SearchString:search + insertNot:insertNot]; +@@ -312,9 +328,9 @@ + + /* not a flag */ + if (insertNot) +- [search appendString:@"not "]; ++ [search appendString:@"NOT "]; + +- if ([lkey isEqualToString:@"date"]) { ++ if ([lkey isEqualToString:@"DATE"] || [lkey isEqualToString:@"RECEIVE-DATE"]) { + NSString *s; + + if (![lvalue isKindOfClass:[NSCalendarDate class]]) { +@@ -322,35 +338,38 @@ + @"expected a NSDate as value"]; + } + +- if ((s = [self imap4OperatorForDateComparisonSelector:lselector]) == nil) ++ if ((s = [self imap4OperatorForDateKeyword:lkey ++ andComparisonSelector:lselector]) == nil) + return [self invalidImap4SearchQualifier:@"unexpected selector"]; + +- // TODO: operator created but NOT added? ++ [search appendString:s]; + + // TODO: much faster without descriptionWithCalendarFormat:?! +- s = [lvalue descriptionWithCalendarFormat:@"%d-%b-%Y"]; ++ s = [lvalue descriptionWithCalendarFormat:@"\"%d-%b-%Y\""]; + [search appendString:s]; + return nil; + } + +- if ([lkey isEqualToString:@"uid"]) { +- if (!sel_eq(lselector, EOQualifierOperatorEqual)) ++ if ([lkey isEqualToString:@"UID"]) { ++ if (!sel_eq(lselector, EOQualifierOperatorEqual)) { + return [self invalidImap4SearchQualifier:@"unexpected qualifier 2"]; ++ } + +- [search appendString:@"uid "]; ++ [search appendString:@"UID "]; + [search appendString:[lvalue stringValue]]; + return nil; + } + +- if ([lkey isEqualToString:@"size"]) { ++ if ([lkey isEqualToString:@"SIZE"]) { + if (sel_eq(lselector, EOQualifierOperatorGreaterThan)) +- [search appendString:@"larger "]; ++ [search appendString:@"LARGER "]; + else if (sel_eq(lselector, EOQualifierOperatorLessThan)) +- [search appendString:@"smaller "]; ++ [search appendString:@"SMALLER "]; + else + return [self invalidImap4SearchQualifier:@"unexpected qualifier 3"]; + + [search appendString:[lvalue stringValue]]; ++ + return nil; + } + +@@ -386,7 +405,7 @@ + if (!sel_eq(lselector, EOQualifierOperatorEqual)) + return [self invalidImap4SearchQualifier:@"unexpected qualifier 5"]; + +- [search appendString:@"header "]; ++ [search appendString:@"HEADER "]; + [search appendString:lkey]; + [search appendString:@" \""]; + [search appendString:[lvalue stringValue]]; +Index: sope-mime/NGImap4/NGImap4ResponseParser.m +=================================================================== +--- sope-mime/NGImap4/NGImap4ResponseParser.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4ResponseParser.m (working copy) +@@ -31,6 +31,7 @@ + @interface NGImap4ResponseParser(ParsingPrivates) + - (BOOL)_parseNumberUntaggedResponse:(NGMutableHashMap *)result_; + - (NSDictionary *)_parseBodyContent; ++- (NSData *) _parseBodyHeaderFields; + + - (NSData *)_parseData; + +@@ -38,6 +39,7 @@ + - (void)_parseContinuationResponseIntoHashMap:(NGMutableHashMap *)result_; + - (BOOL)_parseListOrLSubResponseIntoHashMap:(NGMutableHashMap *)result_; + - (BOOL)_parseCapabilityResponseIntoHashMap:(NGMutableHashMap *)result_; ++- (BOOL)_parseNamespaceResponseIntoHashMap:(NGMutableHashMap *)result_; + - (BOOL)_parseSearchResponseIntoHashMap:(NGMutableHashMap *)result_; + - (BOOL)_parseSortResponseIntoHashMap:(NGMutableHashMap *)result_; + - (BOOL)_parseQuotaRootResponseIntoHashMap:(NGMutableHashMap *)result_; +@@ -84,6 +86,8 @@ + static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self, + BOOL isBodyStructure); + ++static NSArray *_parseLanguages(); ++ + static NSString *_parseBodyString(NGImap4ResponseParser *self, + BOOL _convertString); + static NSString *_parseBodyDecodeString(NGImap4ResponseParser *self, +@@ -111,6 +115,7 @@ + static NSNumber *_parseUnsigned(NGImap4ResponseParser *self); + static NSString *_parseUntil(NGImap4ResponseParser *self, char _c); + static NSString *_parseUntil2(NGImap4ResponseParser *self, char _c1, char _c2); ++static BOOL _endsWithCQuote(NSString *_string); + + static __inline__ NSException *_consumeIfMatch + (NGImap4ResponseParser *self, unsigned char _m); +@@ -488,6 +493,50 @@ + return [self _parseDataIntoRAM:size]; + } + ++/* ++ Similair to _parseData but used to parse something like this : ++ ++ BODY[HEADER.FIELDS (X-PRIORITY)] {17} ++ X-Priority: 1 ++ ++ ) ++ ++ Headers are returned as data, as is. ++*/ ++- (NSData *) _parseBodyHeaderFields ++{ ++ NSData *result; ++ unsigned size; ++ NSNumber *sizeNum; ++ ++ /* we skip until we're ready to parse {length} */ ++ _parseUntil(self, '{'); ++ ++ result = nil; ++ ++ if ((sizeNum = _parseUnsigned(self)) == nil) { ++ NSException *e; ++ ++ e = [[NGImap4ParserException alloc] ++ initWithFormat:@"expect a number between {}"]; ++ [self setLastException:[e autorelease]]; ++ return nil; ++ } ++ _consumeIfMatch(self, '}'); ++ _consumeIfMatch(self, '\n'); ++ ++ if ((size = [sizeNum intValue]) == 0) { ++ [self logWithFormat:@"ERROR(%s): got content size '0'!", ++ __PRETTY_FUNCTION__]; ++ return nil; ++ } ++ ++ if (UseMemoryMappedData && (size > Imap4MMDataBoundary)) ++ return [self _parseDataToFile:size]; ++ ++ return [self _parseDataIntoRAM:size]; ++} ++ + static int _parseTaggedResponse(NGImap4ResponseParser *self, + NGMutableHashMap *result_) + { +@@ -584,6 +633,10 @@ + break; + + case 'N': ++ if (_matchesString(self, "NAMESPACE")) { ++ if ([self _parseNamespaceResponseIntoHashMap:result_]) ++ return; ++ } + if (_parseNoUntaggedResponse(self, result_)) // la: 2 + return; + break; +@@ -648,14 +701,171 @@ + [result_ addObject:_parseUntil(self, '\n') forKey:@"description"]; + } + ++static inline void ++_purifyQuotedString(NSMutableString *quotedString) { ++ unichar *currentChar, *qString, *maxC, *startC; ++ unsigned int max, questionMarks; ++ BOOL possiblyQuoted, skipSpaces; ++ NSMutableString *newString; ++ ++ newString = [NSMutableString string]; ++ ++ max = [quotedString length]; ++ qString = malloc (sizeof (unichar) * max); ++ [quotedString getCharacters: qString]; ++ currentChar = qString; ++ startC = qString; ++ maxC = qString + max; ++ ++ possiblyQuoted = NO; ++ skipSpaces = NO; ++ ++ questionMarks = 0; ++ ++ while (currentChar < maxC) { ++ if (possiblyQuoted) { ++ if (questionMarks == 2) { ++ if ((*currentChar == 'Q' || *currentChar == 'q' ++ || *currentChar == 'B' || *currentChar == 'b') ++ && ((currentChar + 1) < maxC ++ && (*(currentChar + 1) == '?'))) { ++ currentChar++; ++ questionMarks = 3; ++ } ++ else { ++ possiblyQuoted = NO; ++ } ++ } ++ else if (questionMarks == 4) { ++ if (*currentChar == '=') { ++ skipSpaces = YES; ++ possiblyQuoted = NO; ++ currentChar++; ++ [newString appendString: [NSString stringWithCharacters: startC ++ length: (currentChar - startC)]]; ++ startC = currentChar; ++ } ++ else { ++ possiblyQuoted = NO; ++ } ++ } ++ else { ++ if (*currentChar == '?') { ++ questionMarks++; ++ } ++ else if (*currentChar == ' ' && questionMarks != 3) { ++ possiblyQuoted = NO; ++ } ++ } ++ } ++ else if (*currentChar == '=' ++ && ((currentChar + 1) < maxC ++ && (*(currentChar + 1) == '?'))) { ++ [newString appendString: [NSString stringWithCharacters: startC ++ length: (currentChar - startC)]]; ++ startC = currentChar; ++ possiblyQuoted = YES; ++ skipSpaces = NO; ++ currentChar++; ++ questionMarks = 1; ++ } ++ ++ currentChar++; ++ ++ if (skipSpaces) { ++ while (currentChar < maxC ++ && (*currentChar == ' ' ++ || *currentChar == '\t')) ++ currentChar++; ++ skipSpaces = NO; ++ startC = currentChar; ++ } ++ } ++ ++ if (startC < maxC) ++ [newString appendString: [NSString stringWithCharacters: startC ++ length: (currentChar - startC)]]; ++ ++ [quotedString setString: newString]; ++ free (qString); ++} ++ + - (NSString *)_parseQuotedString { ++ NSMutableString *quotedString; ++ NSString *tmpString; ++ BOOL stop; ++ + /* parse a quoted string, eg '"' */ + if (_la(self, 0) == '"') { + _consume(self, 1); +- return _parseUntil(self, '"'); ++ quotedString = [NSMutableString string]; ++ stop = NO; ++ while (!stop) { ++ tmpString = _parseUntil(self, '"'); ++ [quotedString appendString: tmpString]; ++ if(_endsWithCQuote(tmpString)) { ++ [quotedString deleteSuffix: @"\\"]; ++ [quotedString appendString: @"\""]; ++ } ++ else { ++ stop = YES; ++ } ++ } + } ++ else { ++ quotedString = nil; ++ } ++ ++ _purifyQuotedString(quotedString); ++ ++ return quotedString; ++} ++- (NSString *)_parseQuotedStringOrNIL { ++ unsigned char c0; ++ ++ if ((c0 = _la(self, 0)) == '"') ++ return [self _parseQuotedString]; ++ ++ if (c0 == '{') { ++ /* a size indicator, eg '{112}\nkasdjfkja sdj fhj hasdfj hjasdf' */ ++ NSData *data; ++ NSString *s; ++ ++ if ((data = [self _parseData]) == nil) ++ return nil; ++ if (![data isNotEmpty]) ++ return @""; ++ ++ s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; ++ if (s == nil) ++ s = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; ++ if (s == nil) { ++ [self logWithFormat: ++ @"ERROR(%s): could not convert data (%d bytes) into string.", ++ __PRETTY_FUNCTION__, [data length]]; ++ return @"[ERROR: NGImap4 could not parse IMAP4 data string]"; ++ } ++ return [s autorelease]; ++ } ++ ++ if (c0 == 'N' && _matchesString(self, "NIL")) { ++ _consume(self, 3); ++ return (id)null; ++ } + return nil; + } ++- (id)_parseQuotedStringOrDataOrNIL { ++ if (_la(self, 0) == '"') ++ return [self _parseQuotedString]; ++ if (_la(self, 0) == '{') ++ return [self _parseData]; ++ ++ if (_matchesString(self, "NIL")) { ++ _consume(self, 3); ++ return null; ++ } ++ return nil; ++} + - (void)_consumeOptionalSpace { + if (_la(self, 0) == ' ') _consume(self, 1); + } +@@ -685,6 +895,10 @@ + name = [self _parseQuotedString]; + _parseUntil(self, '\n'); + } ++ else if (_la(self, 0) == '{') { ++ name = [self _parseQuotedStringOrNIL]; ++ _parseUntil(self, '\n'); ++ } + else + name = _parseUntil(self, '\n'); + +@@ -723,6 +937,85 @@ + return YES; + } + ++/* support for NAMESPACE extension - RFC2342 */ ++ ++- (NSDictionary *)_parseNamespacePart { ++ NSDictionary *namespacePart; ++ NSString *prefix, *key, *delimiter; ++ NSMutableDictionary *parameters; ++ NSMutableArray *values; ++ ++ _consume(self, 1); /* ( */ ++ prefix = [self _parseQuotedStringOrNIL]; /* "prefix" */ ++ _consume(self, 1); /* */ ++ delimiter = [self _parseQuotedStringOrNIL]; /* "delimiter" */ ++ parameters = [NSMutableDictionary dictionary]; ++ while (_la(self, 0) == ' ') { ++ _consume(self, 1); /* */ ++ key = [self _parseQuotedString]; ++ _consume(self, 1); /* */ ++ values = [NSMutableArray new]; ++ while (_la(self, 0) != ')') { ++ _consume(self, 1); /* ( or */ ++ [values addObject: [self _parseQuotedString]]; ++ } ++ _consume(self, 1); /* ) */ ++ [parameters setObject: values forKey: key]; ++ [values release]; ++ } ++ _consume(self, 1); /* ) */ ++ ++ namespacePart = [NSDictionary dictionaryWithObjectsAndKeys: ++ prefix, @"prefix", ++ delimiter, @"delimiter", ++ parameters, @"parameters", ++ nil]; ++ ++ return namespacePart; ++} ++ ++- (NSArray *)_parseNamespace { ++ NSMutableArray *namespace; ++ ++ namespace = [[NSMutableArray alloc] initWithCapacity: 3]; ++ if (_la(self, 0) == 'N') { ++ namespace = nil; ++ _consume(self, 3); ++ } else { ++ _consume(self, 1); /* ( */ ++ while (_la(self, 0) == '(') { ++ [namespace addObject: [self _parseNamespacePart]]; ++ } ++ _consume(self, 1); /* ) */ ++ } ++ ++ return namespace; ++} ++ ++- (BOOL)_parseNamespaceResponseIntoHashMap:(NGMutableHashMap *)result_ { ++ NSArray *namespace; ++ ++ if (!_matchesString(self, "NAMESPACE ")) ++ return NO; ++ ++ _parseUntil(self, ' '); ++ ++ namespace = [self _parseNamespace]; ++ if (namespace) ++ [result_ addObject:namespace forKey:@"personal"]; ++ _consume(self, 1); ++ namespace = [self _parseNamespace]; ++ if (namespace) ++ [result_ addObject:namespace forKey:@"other users"]; ++ _consume(self, 1); ++ namespace = [self _parseNamespace]; ++ if (namespace) ++ [result_ addObject:namespace forKey:@"shared"]; ++ _consume(self, 1); /* \n */ ++ ++ return YES; ++} ++ + - (BOOL)_parseACLResponseIntoHashMap:(NGMutableHashMap *)result_ { + /* + 21 GETACL INBOX +@@ -1030,10 +1323,15 @@ + _consume(self, 7); + + if (_la(self, 0) == '"') { +- _consume(self, 1); +- name = _parseUntil(self, '"'); ++ name = [self _parseQuotedString]; ++// _consume(self, 1); ++// name = _parseUntil(self, '"'); + _consumeIfMatch(self, ' '); + } ++ else if (_la(self, 0) == '{') { ++ name = [self _parseQuotedStringOrNIL]; ++ _consumeIfMatch(self, ' '); ++ } + else { + name = _parseUntil(self, ' '); + } +@@ -1073,51 +1371,6 @@ + return YES; + } + +-- (NSString *)_parseQuotedStringOrNIL { +- unsigned char c0; +- +- if ((c0 = _la(self, 0)) == '"') +- return [self _parseQuotedString]; +- +- if (c0 == '{') { +- /* a size indicator, eg '{112}\nkasdjfkja sdj fhj hasdfj hjasdf' */ +- NSData *data; +- NSString *s; +- +- if ((data = [self _parseData]) == nil) +- return nil; +- if (![data isNotEmpty]) +- return @""; +- +- s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; +- if (s == nil) { +- [self logWithFormat: +- @"ERROR(%s): could not convert data (%d bytes) into string.", +- __PRETTY_FUNCTION__, [data length]]; +- return @"[ERROR: NGImap4 could not parse IMAP4 data string]"; +- } +- return [s autorelease]; +- } +- +- if (c0 == 'N' && _matchesString(self, "NIL")) { +- _consume(self, 3); +- return (id)null; +- } +- return nil; +-} +-- (id)_parseQuotedStringOrDataOrNIL { +- if (_la(self, 0) == '"') +- return [self _parseQuotedString]; +- if (_la(self, 0) == '{') +- return [self _parseData]; +- +- if (_matchesString(self, "NIL")) { +- _consume(self, 3); +- return null; +- } +- return nil; +-} +- + - (id)_decodeQP:(id)_string headerField:(NSString *)_field { + if (![_string isNotNull]) + return _string; +@@ -1185,7 +1438,7 @@ + route = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; + mailbox = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; + host = [self _parseQuotedStringOrNIL]; [self _consumeOptionalSpace]; +- ++ + if (_la(self, 0) != ')') { + [self logWithFormat:@"WARNING: IMAP4 envelope " + @"address not properly closed (c0=%c,c1=%c): %@", +@@ -1197,6 +1450,7 @@ + address = [[NGImap4EnvelopeAddress alloc] initWithPersonalName:pname + sourceRoute:route mailbox:mailbox + host:host]; ++ + return address; + } + +@@ -1382,7 +1636,15 @@ + #if 0 + [self logWithFormat:@"PARSE KEY: %@", key]; + #endif +- if ([key hasPrefix:@"body["]) { ++ if ([key hasPrefix:@"body[header.fields"]) { ++ NSData *content; ++ ++ if ((content = [self _parseBodyHeaderFields]) != nil) ++ [fetch setObject:content forKey:key]; ++ else ++ [self logWithFormat:@"ERROR: got no body content for key: '%@'",key]; ++ } ++ else if ([key hasPrefix:@"body["]) { + NSDictionary *content; + + if ((content = [self _parseBodyContent]) != nil) +@@ -1594,8 +1856,11 @@ + if (_decode) + data = [data decodeQuotedPrintableValueOfMIMEHeaderField:nil]; + +- return [[[StrClass alloc] initWithData:data encoding:encoding] +- autorelease]; ++ if ([data isKindOfClass: [NSString class]]) ++ return (NSString *) data; ++ else ++ return [[[StrClass alloc] initWithData:data encoding:encoding] ++ autorelease]; + } + else { + str = _parseUntil2(self, ' ', ')'); +@@ -1620,13 +1885,35 @@ + return str; + } + +- + static NSString *_parseBodyString(NGImap4ResponseParser *self, + BOOL _convertString) + { + return _parseBodyDecodeString(self, _convertString, NO /* no decode */); + } + ++static NSArray *_parseLanguages(NGImap4ResponseParser *self) { ++ NSMutableArray *languages; ++ NSString *language; ++ ++ languages = [NSMutableArray array]; ++ if (_la(self, 0) == '(') { ++ while (_la(self, 0) != ')') { ++ _consume(self,1); ++ language = _parseBodyString(self, YES); ++ if ([language length]) ++ [languages addObject: language]; ++ } ++ _consume(self,1); ++ } ++ else { ++ language = _parseBodyString(self, YES); ++ if ([language length]) ++ [languages addObject: language]; ++ } ++ ++ return languages; ++} ++ + static NSDictionary *_parseBodyParameterList(NGImap4ResponseParser *self) + { + NSMutableDictionary *list; +@@ -1646,7 +1933,7 @@ + _consumeIfMatch(self, ' '); + value = _parseBodyDecodeString(self, YES, YES); + +- [list setObject:value forKey:[key lowercaseString]]; ++ if (value) [list setObject:value forKey:[key lowercaseString]]; + } + _consumeIfMatch(self, ')'); + } +@@ -1731,13 +2018,14 @@ + static NSDictionary *_parseSingleBody(NGImap4ResponseParser *self, + BOOL isBodyStructure) { + NSString *type, *subtype, *bodyId, *description, +- *encoding, *bodysize; ++ *result, *encoding, *bodysize; + NSDictionary *parameterList; + NSMutableDictionary *dict; ++ NSArray *languages; + + type = [_parseBodyString(self, YES) lowercaseString]; + _consumeIfMatch(self, ' '); +- subtype = _parseBodyString(self, YES); ++ subtype = [_parseBodyString(self, YES) lowercaseString]; + _consumeIfMatch(self, ' '); + parameterList = _parseBodyParameterList(self); + _consumeIfMatch(self, ' '); +@@ -1762,13 +2050,18 @@ + _consumeIfMatch(self, ' '); + [dict setObject:_parseBodyString(self, YES) forKey:@"lines"]; + } +- else if ([type isEqualToString:@"message"]) { ++ else if ([type isEqualToString:@"message"] ++ && [subtype isEqualToString:@"rfc822"]) { + if (_la(self, 0) != ')') { + _consumeIfMatch(self, ' '); + _consumeIfMatch(self, '('); +- [dict setObject:_parseBodyString(self, YES) forKey:@"date"]; ++ result = _parseBodyString(self, YES); ++ if (result == nil) result = @""; ++ [dict setObject:result forKey:@"date"]; + _consumeIfMatch(self, ' '); +- [dict setObject:_parseBodyString(self, YES) forKey:@"subject"]; ++ result = _parseBodyString(self, YES); ++ if (result == nil) result = @""; ++ [dict setObject:result forKey:@"subject"]; + _consumeIfMatch(self, ' '); + [dict setObject:_parseParenthesizedAddressList(self) forKey:@"from"]; + _consumeIfMatch(self, ' '); +@@ -1783,14 +2076,20 @@ + _consumeIfMatch(self, ' '); + [dict setObject:_parseParenthesizedAddressList(self) forKey:@"bcc"]; + _consumeIfMatch(self, ' '); +- [dict setObject:_parseBodyString(self, YES) forKey:@"in-reply-to"]; ++ result = _parseBodyString(self, YES); ++ if (result == nil) result = @""; ++ [dict setObject:result forKey:@"in-reply-to"]; + _consumeIfMatch(self, ' '); +- [dict setObject:_parseBodyString(self, YES) forKey:@"messageId"]; ++ result = _parseBodyString(self, YES); ++ if (result == nil) result = @""; ++ [dict setObject:result forKey:@"messageId"]; + _consumeIfMatch(self, ')'); + _consumeIfMatch(self, ' '); + [dict setObject:_parseBody(self, isBodyStructure) forKey:@"body"]; + _consumeIfMatch(self, ' '); +- [dict setObject:_parseBodyString(self, YES) forKey:@"bodyLines"]; ++ result = _parseBodyString(self, YES); ++ if (result == nil) result = @""; ++ [dict setObject:result forKey:@"bodyLines"]; + } + } + +@@ -1805,14 +2104,9 @@ + forKey: @"disposition"]; + if (_la(self, 0) != ')') { + _consume(self,1); +- if (_la(self, 0) == '(') { +- [dict setObject: _parseBodyParameterList(self) +- forKey: @"language"]; +- } +- else { +- [dict setObject: _parseBodyString(self, YES) +- forKey: @"language"]; +- } ++ languages = _parseLanguages(self); ++ if ([languages count]) ++ [dict setObject: languages forKey: @"languages"]; + if (_la(self, 0) != ')') { + _consume(self,1); + [dict setObject: _parseBodyString(self, YES) +@@ -1829,6 +2123,7 @@ + static NSDictionary *_parseMultipartBody(NGImap4ResponseParser *self, + BOOL isBodyStructure) { + NSMutableArray *parts; ++ NSArray *languages; + NSString *kind; + NSMutableDictionary *dict; + +@@ -1854,14 +2149,9 @@ + forKey: @"disposition"]; + if (_la(self, 0) != ')') { + _consume(self,1); +- if (_la(self, 0) == '(') { +- [dict setObject: _parseBodyParameterList(self) +- forKey: @"language"]; +- } +- else { +- [dict setObject: _parseBodyString(self, YES) +- forKey: @"language"]; +- } ++ languages = _parseLanguages(self); ++ if ([languages count]) ++ [dict setObject: languages forKey: @"languages"]; + if (_la(self, 0) != ')') { + _consume(self,1); + [dict setObject: _parseBodyString(self, YES) +@@ -2170,6 +2460,21 @@ + } + } + ++static BOOL _endsWithCQuote(NSString *_string){ ++ unsigned int quoteSlashes; ++ int pos; ++ ++ quoteSlashes = 0; ++ pos = [_string length] - 1; ++ while (pos > -1 ++ && [_string characterAtIndex: pos] == '\\') { ++ quoteSlashes++; ++ pos--; ++ } ++ ++ return ((quoteSlashes % 2) == 1); ++} ++ + - (NSException *)exceptionForFailedMatch:(unsigned char)_match + got:(unsigned char)_avail + { +@@ -2225,9 +2530,9 @@ + [s release]; + + if (c == '\n') { +- if ([self->serverResponseDebug cStringLength] > 2) { ++ if ([self->serverResponseDebug lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding] > 2) { + fprintf(stderr, "S[%p]: %s", self, +- [self->serverResponseDebug cString]); ++ [self->serverResponseDebug cStringUsingEncoding:NSISOLatin1StringEncoding]); + } + [self->serverResponseDebug release]; + self->serverResponseDebug = +Index: sope-mime/NGImap4/ChangeLog +=================================================================== +--- sope-mime/NGImap4/ChangeLog (revision 1664) ++++ sope-mime/NGImap4/ChangeLog (working copy) +@@ -1,3 +1,92 @@ ++2010-01-05 Wolfgang Sourdeau ++ ++ * NGImap4ResponseParser.m (_parseUntaggedResponse): now accepts ++ the "NAMESPACE" response and parse accordingly by making use of ++ the appropriate new method. ++ ++ * NGImap4ResponseNormalizer.m (-normalizeNamespaceResponse): ++ self-explicit new method. ++ ++ * NGImap4Connection.m (-subfolderForURL:, -allFoldersForURL:): ++ differenciate both methods by having "subfolder..." use the "%" ++ wild card and "allFolders" the "*" wildcard. ++ (-cachedHierarchyResultsForURL): now accepts a url parameter so ++ in order to maintain multiple caches depending on the queried ++ namespace. ++ (SOGoMailGetDirectChildren): if the array count is < 2, we must ++ not return since certain implementations may not return the ++ current folder. ++ ++ * NGImap4Client.m (-namespace): new method implementing the ++ "NAMESPACE" command. ++ (-lsub:pattern:): we now sanitize the "prefix" particle of the ++ LSUB command. ++ ++2009-11-25 Wolfgang Sourdeau ++ ++ * NSString+Imap4.m (_encodeToModifiedUTF7): handle the case where ++ the leftOver is 0 by "chance" after the first 2 cycles. This ++ can happen when coding characters having a bitmask with 6 zeroes ++ in a row. ++ ++2009-10-06 Wolfgang Sourdeau ++ ++ * NGImap4Client.m (-delete:): if the folder we want to delete is ++ the same as self->selectedFolder, we unselect it first to ensure a ++ "SELECT" happens if a new folder with the same name is created. ++ ++ * EOQualifier+IMAPAdditions.m ++ (-imap4OperatorForDateKeyword:andComparisonSelector:): modified ++ operator handler to handle "receive-date" search key as well as ++ "date", prefixing the real filter with "sent" or not. ++ ++2009-09-22 Wolfgang Sourdeau ++ ++ * NGImap4Client.m (_sopeSORT:qualifier:encoding:): added support ++ for sorting by message size. ++ ++2009-07-01 Wolfgang Sourdeau ++ ++ * NGImap4Connection.m (-initWithClient:password:): we need to copy ++ the imap4Separator, otherwise it will be released when the connection ++ is deallocated. ++ ++2009-06-15 Wolfgang Sourdeau ++ ++ * NSString+Imap4.m (-stringByEncodingImap4FolderName, ++ -stringByDecodingImap4FolderName): reimplemented the original ++ methods in a unicode-safe way, thereby simplifying the code at the ++ same time. ++ ++ * NGImap4Functions.m (SaneFolderName): new function designed to ++ sanitize folder names prior to using them in IMAP commands. ++ ++2008-10-23 Wolfgang Sourdeau ++ ++ * NGImap4Client.m ([NGImap -sort:qualifier:encoding:]): message ++ without date that are sorted on servers which do not have the SORT ++ capability are now given the current date as a work-around. ++ ++2008-09-22 Wolfgang Sourdeau ++ ++ * NGImap4Connection.m ([NGImap -doesMailboxExistAtURL:]): restore ++ the previously selected folder state. ++ ++2008-09-19 Wolfgang Sourdeau ++ ++ * NGImap4Client.m ([NGImap -select:]): simplified method by ++ removing the need for storing the previous folder before releasing ++ it. This strangely seems to fix a crash with gnustep 1.14. ++ ++2008-09-01 Ludovic Marcotte ++ ++ * NGImap4ConnectionManager.m: implemented _garbageCollect. ++ ++2008-08-28 Wolfgang Sourdeau ++ ++ * NGImap4Client.m ([NGImap -unselect]): new method to send ++ "UNSELECT" to the imap server. ++ + 2007-08-24 Wolfgang Sourdeau + + * NGImap4Connection.m: some fix for folders ending with a slash (OGo +Index: sope-mime/NGImap4/NGImap4ConnectionManager.m +=================================================================== +--- sope-mime/NGImap4/NGImap4ConnectionManager.m (revision 1664) ++++ sope-mime/NGImap4/NGImap4ConnectionManager.m (working copy) +@@ -38,6 +38,9 @@ + debugCache = [ud boolForKey:@"NGImap4EnableIMAP4CacheDebug"]; + poolingOff = [ud boolForKey:@"NGImap4DisableIMAP4Pooling"]; + ++ if ([ud objectForKey:@"NGImap4PoolingCleanupInterval"]) ++ PoolScanInterval = [[ud objectForKey:@"NGImap4PoolingCleanupInterval"] doubleValue]; ++ + if (debugOn) NSLog(@"Note: NGImap4EnableIMAP4Debug is enabled!"); + if (poolingOff) NSLog(@"WARNING: IMAP4 connection pooling is disabled!"); + } +@@ -53,18 +56,17 @@ + if ((self = [super init])) { + if (!poolingOff) { + self->urlToEntry = [[NSMutableDictionary alloc] initWithCapacity:256]; ++ self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: ++ PoolScanInterval ++ target:self selector:@selector(_garbageCollect:) ++ userInfo:nil repeats:YES] retain]; + } +- +- self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: +- PoolScanInterval +- target:self selector:@selector(_garbageCollect:) +- userInfo:nil repeats:YES] retain]; + } + return self; + } + + - (void)dealloc { +- if (self->gcTimer) [self->gcTimer invalidate]; ++ [self->gcTimer invalidate]; + [self->urlToEntry release]; + [self->gcTimer release]; + [super dealloc]; +@@ -91,6 +93,25 @@ + + - (void)_garbageCollect:(NSTimer *)_timer { + // TODO: scan for old IMAP4 channels ++ NGImap4Connection *entry; ++ NSDate *now; ++ NSArray *a; ++ int i; ++ ++ a = [self->urlToEntry allKeys]; ++ now = [NSDate date]; ++ ++ for (i = 0; i < [a count]; i++) ++ { ++ entry = [self->urlToEntry objectForKey: [a objectAtIndex: i]]; ++ ++ if ([now timeIntervalSinceDate: [entry creationTime]] > PoolScanInterval) ++ { ++ [[entry client] logout]; ++ [self->urlToEntry removeObjectForKey: [a objectAtIndex: i]]; ++ } ++ } ++ + [self debugWithFormat:@"should collect IMAP4 channels (%d active)", + [self->urlToEntry count]]; + } +@@ -105,34 +126,42 @@ + NGImap4Connection *entry; + NGImap4Client *client; + ++ if (poolingOff) { ++ client = [self imap4ClientForURL:_url password:_p]; ++ entry = [[NGImap4Connection alloc] initWithClient:client ++ password:_p]; ++ return [entry autorelease]; ++ } ++ else { + /* check cache */ + +- if ((entry = [self entryForURL:_url]) != nil) { +- if ([entry isValidPassword:_p]) { ++ if ((entry = [self entryForURL:_url]) != nil) { ++ if ([entry isValidPassword:_p]) { ++ if (debugCache) ++ [self logWithFormat:@"valid password, reusing cache entry ..."]; ++ return entry; ++ } ++ ++ /* different password, password could have changed! */ + if (debugCache) +- [self logWithFormat:@"valid password, reusing cache entry ..."]; +- return entry; ++ [self logWithFormat:@"different password than cached entry: %@", _url]; ++ entry = nil; + } +- +- /* different password, password could have changed! */ +- if (debugCache) +- [self logWithFormat:@"different password than cached entry: %@", _url]; +- entry = nil; +- } +- else +- [self debugWithFormat:@"no connection cached yet for url: %@", _url]; ++ else ++ [self debugWithFormat:@"no connection cached yet for url: %@", _url]; + +- /* try to login */ ++ /* try to login */ + +- client = [entry isValidPassword:_p] +- ? [entry client] +- : [self imap4ClientForURL:_url password:_p]; ++ client = [entry isValidPassword:_p] ++ ? [entry client] ++ : [self imap4ClientForURL:_url password:_p]; ++ ++ if (client == nil) ++ return nil; + +- if (client == nil) +- return nil; +- + /* sideeffect of -imap4ClientForURL:password: is to create a cache entry */ +- return [self entryForURL:_url]; ++ return [self entryForURL:_url]; ++ } + } + + /* client object */ +Index: sope-mime/NGImap4/NSString+Imap4.m +=================================================================== +--- sope-mime/NGImap4/NSString+Imap4.m (revision 1664) ++++ sope-mime/NGImap4/NSString+Imap4.m (working copy) +@@ -20,117 +20,86 @@ + 02111-1307, USA. + */ + ++#import ++ + #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(unsigned char *_target, unsigned _targetLen, +- unsigned *usedBytes_ , +- unsigned char **buffer_, +- int *bufLen_, int maxBuf); +- + @implementation NSString(Imap4) + ++static unsigned int _encodeToModifiedUTF7(unichar *_char, unsigned char *result_, ++ unsigned int *cntRes_); ++static unsigned int _decodeOfModifiedUTF7(unsigned char *_source, unichar *result_, ++ unsigned int *cntRes_ ); ++ + - (NSString *)stringByEncodingImap4FolderName { +- // TBD: this is restricted to Latin1, should be fixed to UTF-8 +- /* dude.d& --> dude.d&- */ +- unsigned char *buf = NULL; ++ unichar *buf = NULL; + unsigned char *res = NULL; + unsigned int len = 0; + unsigned int cnt = 0; + unsigned int cntRes = 0; + NSString *result = nil; +- NSData *data; + +- 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:(char *)buf]; ++ len = [self length]; ++ buf = NSZoneMalloc(NULL, (len + 1) * sizeof(unichar)); ++ [self getCharacters: buf]; ++ buf[len] = 0; + ++ /* 1 * '&', 3 for the max bytes / char, 1 * '-' */ ++ res = NSZoneMalloc(NULL, ((len * 5) + 1) * sizeof(char)); ++ + while (cnt < len) { +- int c = buf[cnt]; ++ unichar 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] = '-'; +- cntRes++; +- cnt++; +- } ++ res[cntRes++] = '&'; ++ cnt += _encodeToModifiedUTF7(buf + cnt, res + cntRes, &cntRes); ++ res[cntRes++] = '-'; + } + } ++ cnt++; + } +- if (buf != NULL) free(buf); buf = NULL; ++ if (buf != NULL) NSZoneFree(NULL, buf); + +- data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes +- freeWhenDone:YES]; +- result = [[NSString alloc] initWithData:data +- encoding:NSISOLatin1StringEncoding]; +- [data release]; data = nil; +- +- return [result autorelease]; ++ res[cntRes] = 0; ++ result = [NSString stringWithCString: (char *) res ++ encoding: NSISOLatin1StringEncoding]; ++ ++ return result; + } + + - (NSString *)stringByDecodingImap4FolderName { +- // TBD: this is restricted to Latin1, should be fixed to UTF-8 +- /* dude/d&- --> dude/d& */ + unsigned char *buf; +- unsigned char *res; ++ unichar *res; + unsigned int len; + unsigned int cnt = 0; + unsigned int cntRes = 0; + NSString *result = nil; +- NSData *data; ++// NSData *data; + +- if ((len = [self cStringLength]) == 0) ++ if ((len = [self lengthOfBytesUsingEncoding: NSISOLatin1StringEncoding]) == 0) + return @""; +- +- buf = calloc(len + 3, sizeof(unsigned char)); +- res = calloc(len + 3, sizeof(unsigned char)); ++ ++ buf = NSZoneMalloc(NULL, (len + 1) * sizeof(unsigned char)); ++ ++ if ([self getCString:(char *)buf maxLength: len + 1 ++ encoding: NSISOLatin1StringEncoding] == NO) { ++ NSZoneFree(NULL, buf); ++ return @""; ++ } + buf[len] = '\0'; +- res[len] = '\0'; +- +- [self getCString:(char *)buf]; +- +- while (cnt < (len - 1)) { /* &- */ ++ ++ res = NSZoneMalloc(NULL, (len + 1) * sizeof(unichar)); ++ ++ while (cnt < len) { /* &- */ + unsigned char c; + + c = buf[cnt]; +@@ -141,29 +110,7 @@ + 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; ++ cnt += _decodeOfModifiedUTF7(buf + cnt + 1, res + cntRes, &cntRes) + 1; + } + } + else { +@@ -171,20 +118,133 @@ + cnt++; + } + } +- if (cnt < len) +- res[cntRes++] = buf[cnt++]; +- +- if (buf != NULL) free(buf); buf = NULL; + +- data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes +- freeWhenDone:YES]; +- result = [[NSString alloc] initWithData:data +- encoding:NSISOLatin1StringEncoding]; +- [data release]; data = nil; +- +- return [result autorelease]; ++ if (buf != NULL) NSZoneFree(NULL, buf); ++ ++ res[cntRes] = 0; ++ result = [NSString stringWithCharacters: res length: cntRes]; ++ ++ return result; + } + ++/* check metamail output for correctness */ ++ ++static unsigned char basis_64[] = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++ ++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 unsigned int _encodeToModifiedUTF7(unichar *_char, unsigned char *result_, ++ unsigned int *cntRes_) ++{ ++ unsigned int processedSrc, processedDest, cycle; ++ unichar c; ++ char leftover; ++ BOOL hasLeftOver; ++ ++ processedSrc = 0; ++ processedDest = 0; ++ cycle = 0; ++ leftover = 0; ++ ++ c = *_char; ++ while (c > 126 || (c > 0 && c < 32)) { ++ if (cycle == 0) { ++ *(result_ + processedDest) = basis_64[(c >> 10) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 4) & 0x3f]; ++ leftover = (c << 2); ++ hasLeftOver = YES; ++ processedDest += 2; ++ cycle = 1; ++ } ++ else if (cycle == 1) { ++ *(result_ + processedDest) = basis_64[(leftover | (c >> 14)) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 8) & 0x3f]; ++ *(result_ + processedDest + 2) = basis_64[(c >> 2) & 0x3f]; ++ leftover = (c << 4); ++ hasLeftOver = YES; ++ processedDest += 3; ++ cycle = 2; ++ } ++ else if (cycle == 2) { ++ *(result_ + processedDest) = basis_64[(leftover | (c >> 12)) & 0x3f]; ++ *(result_ + processedDest + 1) = basis_64[(c >> 6) & 0x3f]; ++ *(result_ + processedDest + 2) = basis_64[c & 0x3f]; ++ leftover = 0; ++ hasLeftOver = NO; ++ processedDest += 3; ++ cycle = 0; ++ } ++ processedSrc++; ++ c = *(_char + processedSrc); ++ } ++ if (hasLeftOver) { ++ *(result_ + processedDest) = basis_64[leftover & 0x3f]; ++ processedDest++; ++ } ++ processedSrc--; ++ *cntRes_ += processedDest; ++ ++ return processedSrc; ++} ++ ++static unsigned int _decodeOfModifiedUTF7(unsigned char *_source, unichar *result_, ++ unsigned int *cntRes_) ++{ ++ unsigned int processedSrc, processedDest; ++ unsigned char c, decoded; ++ unichar currentRes; ++ int shift; ++ ++ processedSrc = 0; ++ processedDest = 0; ++ shift = 10; ++ currentRes = 0; ++ ++ c = *_source; ++ while (c != 0 && c != '-') { ++ decoded = index_64[c]; ++ if (shift < 0) { ++ currentRes |= (decoded >> (shift * -1)); ++ *(result_ + processedDest) = currentRes; ++ processedDest++; ++ shift += 16; ++ currentRes = (decoded << shift); ++ } else { ++ currentRes |= (decoded << shift); ++ if (shift == 0) { ++ *(result_ + processedDest) = currentRes; ++ processedDest++; ++ currentRes = 0; ++ shift = 16; ++ } ++ } ++ shift -= 6; ++ processedSrc++; ++ c = *(_source + processedSrc); ++ } ++ if (shift != 10) { ++ *(result_ + processedDest) = currentRes; ++ } ++ if (c == '-') ++ processedSrc++; ++ ++ *cntRes_ += processedDest; ++ ++ return processedSrc; ++} ++ + - (NSString *)stringByEscapingImap4Password { + // TODO: perf + unichar *buffer; +@@ -193,12 +253,12 @@ + NSString *s; + + len = [self length]; +- chars = calloc(len + 2, sizeof(unichar)); ++ chars = NSZoneCalloc(NULL, len + 2, sizeof(unichar)); + [self getCharacters:chars]; +- +- buffer = calloc(len * 2 + 2, sizeof(unichar)); ++ ++ buffer = NSZoneCalloc(NULL, len * 2 + 2, sizeof(unichar)); + buffer[len * 2] = '\0'; +- ++ + for (i = 0, j = 0; i < len; i++, j++) { + BOOL conv = NO; + +@@ -224,209 +284,11 @@ + } + buffer[j] = chars[i]; + } +- if (chars != NULL) free(chars); chars = NULL; ++ if (chars != NULL) NSZoneFree(NULL, chars); + + s = [NSString stringWithCharacters:buffer length:j]; +- if (buffer != NULL) free(buffer); buffer = NULL; ++ + return s; + } + + @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(unsigned 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; +-} +Index: sope-mime/NGImap4/NGImap4Functions.h +=================================================================== +--- sope-mime/NGImap4/NGImap4Functions.h (revision 1664) ++++ sope-mime/NGImap4/NGImap4Functions.h (working copy) +@@ -58,4 +58,6 @@ + id_folder); + BOOL _createSubFolderWithName(id self, NSString *_name, BOOL _app); + ++NSString *SaneFolderName(NSString *folderName); ++ + #endif /* __NGMime_NGImap4_NGImap4Functions_H__ */ +Index: sope-mime/NGMail/NGMailAddressParser.h +=================================================================== +--- sope-mime/NGMail/NGMailAddressParser.h (revision 1664) ++++ sope-mime/NGMail/NGMailAddressParser.h (working copy) +@@ -24,7 +24,9 @@ + + #import + +-@class NSData, NSString, NSArray; ++#import ++ ++@class NSData, NSArray; + @class NGMailAddressList; + + /* +@@ -34,16 +36,16 @@ + @interface NGMailAddressParser : NSObject + { + @private +- unsigned char *data; +- int dataPos; +- int errorPos; +- int maxLength; ++ unichar *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; +++ (id)mailAddressParserWithCString:(const char *)_cString; ++- (id)initWithString:(NSString *)_str; + + /* parsing */ + +Index: sope-mime/NGMail/NGMimeMessageGenerator.m +=================================================================== +--- sope-mime/NGMail/NGMimeMessageGenerator.m (revision 1664) ++++ sope-mime/NGMail/NGMimeMessageGenerator.m (working copy) +@@ -86,37 +86,40 @@ + char *des = NULL; + unsigned int cnt; + BOOL doEnc; +- NSString *str; ++// NSString *str; + + // TODO: this s***s big time! ++// NSLog (@"class: '%@'", NSStringFromClass ([_data class])); ++// #if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY ++// str = [[NSString alloc] initWithData:_data ++// encoding:NSISOLatin1StringEncoding]; ++// str = [str autorelease]; ++ ++// #else ++// str = [[NSString alloc] initWithData:_data ++// encoding:NSISOLatin9StringEncoding]; ++// #endif ++// bytes = [str cString]; ++// length = [str cStringLength]; + +-#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]; +- ++ bytes = [_data bytes]; ++ length = [_data length]; ++ + /* check whether we need to encode */ +- +- for (cnt = 0, doEnc = NO; cnt < length; cnt++) { +- if ((unsigned char)bytes[cnt] > 127) { ++ cnt = 0; ++ doEnc = NO; ++ while (!doEnc && cnt < length) ++ if ((unsigned char)bytes[cnt] > 127) + doEnc = YES; +- break; +- } +- } +- ++ else ++ cnt++; ++ + if (!doEnc) + return _data; + + /* encode quoted printable */ + { +- char iso[] = "=?iso-8859-15?q?"; ++ char iso[] = "=?utf-8?q?"; + unsigned isoLen = 16; + char isoEnd[] = "?="; + unsigned isoEndLen = 2; +Index: sope-mime/NGMail/NGMailAddressParser.m +=================================================================== +--- sope-mime/NGMail/NGMailAddressParser.m (revision 1664) ++++ sope-mime/NGMail/NGMailAddressParser.m (working copy) +@@ -52,9 +52,9 @@ + StrClass = [NSString class]; + } + +-static inline NSString *mkStrObj(const unsigned char *s, unsigned int l) { ++static inline NSString *mkStrObj(const unichar *s, unsigned int l) { + // TODO: unicode +- return [(NSString *)[StrClass alloc] initWithCString:(char *)s length:l]; ++ return [(NSString *)[StrClass alloc] initWithCharacters:s length:l]; + } + + static inline id parseWhiteSpaces(NGMailAddressParser *self, BOOL _guessMode) { +@@ -84,7 +84,7 @@ + int keepPos = self->dataPos; // keep reference for backtracking + id returnValue = nil; + BOOL isAtom = YES; +- unsigned char text[self->maxLength + 2]; // token text ++ unichar text[self->maxLength + 2]; // token text + int length = 0; // token text length + BOOL done = NO; + +@@ -94,7 +94,7 @@ + done = YES; + } + else { +- register unsigned char c = self->data[self->dataPos]; ++ register unichar c = self->data[self->dataPos]; + + switch (c) { + case '(' : case ')': case '<': case '>': +@@ -162,7 +162,7 @@ + int keepPos = self->dataPos; // keep reference for backtracking + id returnValue = nil; + BOOL isQText = YES; +- unsigned char text[self->maxLength + 4]; // token text ++ unichar text[self->maxLength + 4]; // token text + int length = 0; // token text length + BOOL done = YES; + +@@ -172,9 +172,9 @@ + done = YES; + } + else { +- register char c = self->data[self->dataPos]; ++ register unichar c = self->data[self->dataPos]; + +- switch ((int)c) { ++ switch (c) { + case '"' : + case '\\': + case 13 : +@@ -215,7 +215,7 @@ + int keepPos = self->dataPos; // keep reference for backtracking + id returnValue = nil; + BOOL isDText = YES; +- unsigned char text[self->maxLength]; // token text ++ unichar text[self->maxLength]; // token text + int length = 0; // token text length + BOOL done = YES; + +@@ -225,9 +225,9 @@ + done = YES; + } + else { +- register char c = self->data[self->dataPos]; ++ register unichar c = self->data[self->dataPos]; + +- switch ((int)c) { ++ switch (c) { + case '[': case ']': + case '\\': case 13: + isDText = (length > 0); +@@ -320,42 +320,47 @@ + /* constructors */ + + + (id)mailAddressParserWithData:(NSData *)_data { +- return [[(NGMailAddressParser *)[self alloc] +- initWithCString:[_data bytes] +- length:[_data length]] autorelease]; ++ NSString *uniString; ++ ++ uniString = [NSString stringWithCharacters:(unichar *)[_data bytes] ++ length:([_data length] / sizeof(unichar))]; ++ ++ return [(NGMailAddressParser *)self mailAddressParserWithString:uniString]; + } ++ + + (id)mailAddressParserWithCString:(char *)_cString { +- return [[(NGMailAddressParser *)[self alloc] +- initWithCString:(unsigned char *)_cString +- length:strlen(_cString)] autorelease]; ++ NSString *nsCString; ++ ++ nsCString = [NSString stringWithCString:_cString]; ++ ++ return [(NGMailAddressParser *)self mailAddressParserWithString:nsCString]; + } +-- (id)initWithCString:(const unsigned char *)_cstr length:(int unsigned)_len { ++ +++ (id)mailAddressParserWithString:(NSString *)_string { ++ return [[(NGMailAddressParser *)[self alloc] initWithString:_string] ++ autorelease]; ++} ++ ++- (id)initWithString:(NSString *)_str { + if ((self = [super init])) { + // TODO: remember some string encoding? +- self->data = (unsigned char *)_cstr; +- self->maxLength = _len; ++ self->maxLength = [_str length]; ++ self->data = malloc(self->maxLength*sizeof(unichar)); ++ [_str getCharacters:self->data]; + self->dataPos = 0; + self->errorPos = -1; + } + return self; + } + +-- (id)initWithString:(NSString *)_str { +- // TODO: unicode +- return [self initWithCString:(unsigned char *)[_str cString] +- length:[_str cStringLength]]; +-} +- + - (id)init { +- return [self initWithCString:NULL length:0]; ++ return [self initWithString:nil]; + } + +-+ (id)mailAddressParserWithString:(NSString *)_string { +- return [[(NGMailAddressParser *)[self alloc] initWithString:_string] +- autorelease]; +-} +- + - (void)dealloc { ++ if (self->data != NULL) { ++ free(self->data); ++ } + self->data = NULL; + self->maxLength = 0; + self->dataPos = 0; +Index: sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m +=================================================================== +--- sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (revision 1664) ++++ sope-mime/NGMime/NGMimeRFC822DateHeaderFieldParser.m (working copy) +@@ -19,88 +19,45 @@ + 02111-1307, USA. + */ + ++#ifdef HAVE_STRNDUP ++#define _GNU_SOURCE 1 ++#endif ++ ++#include ++ + #include "NGMimeHeaderFieldParser.h" + #include "NGMimeHeaderFields.h" + #include "NGMimeUtilities.h" + #include "common.h" +-#include + ++#ifndef HAVE_STRNDUP ++char *strndup(const char *str, size_t len) ++{ ++ char *dup = (char *)malloc(len+1); ++ if (dup) { ++ strncpy(dup,str,len); ++ dup[len]= '\0'; ++ } ++ return dup; ++} ++#endif ++ + @implementation NGMimeRFC822DateHeaderFieldParser + +-static Class CalDateClass = Nil; +-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 *gmt0530 = 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; ++static NSTimeZone *gmt = nil; ++static NSTimeZone *met = nil; + + + (int)version { + return 2; + } ++ + + (void)initialize { + static BOOL didInit = NO; +- Class TzClass; + if (didInit) return; + didInit = YES; + +- CalDateClass = [NSCalendarDate class]; +- +- /* timezones which were actually used in a maillist mailbox */ +- TzClass = [NSTimeZone class]; +- gmt = [[TzClass timeZoneWithName:@"GMT"] retain]; +- met = [[TzClass timeZoneWithName:@"MET"] retain]; +- gmt01 = [[TzClass timeZoneForSecondsFromGMT: 1 * (60 * 60)] retain]; +- gmt02 = [[TzClass timeZoneForSecondsFromGMT: 2 * (60 * 60)] retain]; +- gmt03 = [[TzClass timeZoneForSecondsFromGMT: 3 * (60 * 60)] retain]; +- gmt04 = [[TzClass timeZoneForSecondsFromGMT: 4 * (60 * 60)] retain]; +- gmt05 = [[TzClass timeZoneForSecondsFromGMT: 5 * (60 * 60)] retain]; +- gmt06 = [[TzClass timeZoneForSecondsFromGMT: 6 * (60 * 60)] retain]; +- gmt07 = [[TzClass timeZoneForSecondsFromGMT: 7 * (60 * 60)] retain]; +- gmt08 = [[TzClass timeZoneForSecondsFromGMT: 8 * (60 * 60)] retain]; +- gmt09 = [[TzClass timeZoneForSecondsFromGMT: 9 * (60 * 60)] retain]; +- gmt10 = [[TzClass timeZoneForSecondsFromGMT: 10 * (60 * 60)] retain]; +- gmt11 = [[TzClass timeZoneForSecondsFromGMT: 11 * (60 * 60)] retain]; +- gmt12 = [[TzClass timeZoneForSecondsFromGMT: 12 * (60 * 60)] retain]; +- gmtM01 = [[TzClass timeZoneForSecondsFromGMT: -1 * (60 * 60)] retain]; +- gmtM02 = [[TzClass timeZoneForSecondsFromGMT: -2 * (60 * 60)] retain]; +- gmtM03 = [[TzClass timeZoneForSecondsFromGMT: -3 * (60 * 60)] retain]; +- gmtM04 = [[TzClass timeZoneForSecondsFromGMT: -4 * (60 * 60)] retain]; +- gmtM05 = [[TzClass timeZoneForSecondsFromGMT: -5 * (60 * 60)] retain]; +- gmtM06 = [[TzClass timeZoneForSecondsFromGMT: -6 * (60 * 60)] retain]; +- gmtM07 = [[TzClass timeZoneForSecondsFromGMT: -7 * (60 * 60)] retain]; +- gmtM08 = [[TzClass timeZoneForSecondsFromGMT: -8 * (60 * 60)] retain]; +- gmtM09 = [[TzClass timeZoneForSecondsFromGMT: -9 * (60 * 60)] retain]; +- gmtM10 = [[TzClass timeZoneForSecondsFromGMT:-10 * (60 * 60)] retain]; +- gmtM11 = [[TzClass timeZoneForSecondsFromGMT:-11 * (60 * 60)] retain]; +- gmtM12 = [[TzClass timeZoneForSecondsFromGMT:-12 * (60 * 60)] retain]; +- gmtM13 = [[TzClass timeZoneForSecondsFromGMT:-13 * (60 * 60)] retain]; +- gmtM14 = [[TzClass timeZoneForSecondsFromGMT:-14 * (60 * 60)] retain]; +- +- gmt0530 = [[TzClass timeZoneForSecondsFromGMT:5 * (60*60) + (30*60)] retain]; ++ gmt = [[NSTimeZone timeZoneWithName:@"GMT"] retain]; ++ met = [[NSTimeZone timeZoneWithName:@"MET"] retain]; + } + + /* +@@ -111,7 +68,7 @@ + TODO: use an own parser for that. + */ + +-static int parseMonthOfYear(unsigned char *s, unsigned int len) { ++static int parseMonthOfYear(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 +@@ -147,162 +104,110 @@ + } + } + +-static NSTimeZone *parseTimeZone(unsigned char *s, unsigned int len) { ++static int offsetFromTZAbbreviation(const char **p) { ++ NSString *abbreviation; ++ NSTimeZone *offsetTZ; ++ unsigned int length; ++ ++ length = 0; ++ while (isalpha(*(*p+length))) ++ length++; ++ abbreviation = [[NSString alloc] initWithBytes: *p ++ length: length - 1 ++ encoding: NSISOLatin1StringEncoding]; ++ offsetTZ = [NSTimeZone timeZoneWithAbbreviation: abbreviation]; ++ [abbreviation release]; ++ *p += length; ++ ++ return [offsetTZ secondsFromGMT]; ++} ++ ++static inline char *digitsString(const char *string) { ++ const char *p; ++ unsigned int len; ++ ++ p = string; ++ while (!isdigit(*p)) ++ p++; ++ len = 0; ++ while (isdigit(*(p + len))) ++ len++; ++ ++ return strndup(p, len); ++} ++ ++static NSTimeZone *parseTimeZone(const char *s, unsigned int len) { + /* + WARNING: failed to parse RFC822 timezone: '+0530' \ + (value='Tue, 13 Jul 2004 21:39:28 +0530') + TODO: this is because libFoundation doesn't accept 'GMT+0530' as input. + */ +- char *p = (char *)s; ++ char *newString, *digits; ++ const char *p; + 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' +- } +- } +- +- /* special case for GMT+0530 */ +- if (strncmp((char *)s, "+0530", 5) == 0) +- return gmt0530; +- } +- 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((char *)tmp, p, 3); +- tmp[3] = '0'; +- tmp[4] = '0'; +- tmp[5] = '\0'; +- return parseTimeZone(tmp, 5); +- } +- } ++ unsigned int hours, minutes, seconds, remaining; ++ int sign; ++ ++ sign = 1; ++ hours = 0; ++ minutes = 0; ++ seconds = 0; ++ ++ newString = strndup(s, len); ++ p = newString; ++ ++ if (isalpha(*p)) ++ seconds = offsetFromTZAbbreviation(&p); ++ while (isspace(*p)) ++ p++; ++ while (*p == '+' || *p == '-') { ++ if (*p == '-') ++ sign = -sign; ++ p++; + } +- 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; +- } +- } ++ digits = digitsString(p); ++ p = digits; ++ remaining = strlen(p); ++ switch(remaining) { ++ case 6: /* hhmmss */ ++ seconds += (10 * (*(p + remaining - 2) - 48) ++ + *(p + remaining - 1) - 48); ++ case 4: /* hhmm */ ++ hours += 10 * (*p - 48); ++ p++; ++ case 3: /* hmm */ ++ hours += (*p - 48); ++ p++; ++ minutes += 10 * (*p - 48) + *(p + 1) - 48; ++ break; ++ case 2: /* hh */ ++ hours += 10 * (*p - 48) + *(p + 1) - 48; ++ break; ++ default: ++ NSLog (@"parseTimeZone: cannot parse time notation '%s'", newString); + } +- else if (len == 3) { +- if (strcasecmp((char *)s, "GMT") == 0) return gmt; +- if (strcasecmp((char *)s, "UTC") == 0) return gmt; +- if (strcasecmp((char *)s, "MET") == 0) return met; +- if (strcasecmp((char *)s, "CET") == 0) return met; +- } +- +- if (isalpha(*s)) { +- ts = [[NSString alloc] initWithCString:(char *)s length:len]; +- } +- else { +- char buf[len + 5]; +- +- buf[0] = 'G'; buf[1] = 'M'; buf[2] = 'T'; +- if (*s == '+' || *s == '-') { +- strcpy(&(buf[3]), (char *)s); +- } +- else { +- buf[3] = '+'; +- strcpy(&(buf[4]), (char *)s); +- } +- ts = [[NSString alloc] initWithCString:buf]; +- } +-#if 1 +- NSLog(@"%s: RFC822 TZ Parser: expensive: '%@'", __PRETTY_FUNCTION__, ts); +-#endif +- tz = [NSTimeZone timeZoneWithAbbreviation:ts]; +- [ts release]; ++ free(digits); ++ ++ seconds += sign * (3600 * hours + 60 * minutes); ++ tz = [NSTimeZone timeZoneForSecondsFromGMT: seconds]; ++ free(newString); ++ + return tz; + } + + - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field { + // TODO: use UNICODE + NSCalendarDate *date = nil; +- unsigned char buf[256]; +- unsigned char *bytes = buf, *pe; ++ char *bytes, *pe; + unsigned length = 0; + NSTimeZone *tz = nil; + char dayOfMonth, monthOfYear, hour, minute, second; + short year; + BOOL flag; +- +- if ((length = [_data cStringLength]) > 254) { +- [self logWithFormat: +- @"header field value to large for date parsing: '%@'(%i)", +- _data, length]; +- length = 254; +- } +- +- [_data getCString:(char *)buf maxLength:length]; +- buf[length] = '\0'; +- ++ ++ length = [_data lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; ++ bytes = [_data cStringUsingEncoding: NSUTF8StringEncoding]; ++ + /* remove leading chars (skip to first digit, the day of the month) */ + while (length > 0 && (!isdigit(*bytes))) { + bytes++; +@@ -312,7 +217,7 @@ + if (length == 0) { + NSLog(@"WARNING(%s): empty value for header field %@ ..", + __PRETTY_FUNCTION__, _field); +- return [CalDateClass date]; ++ return [NSCalendarDate date]; + } + + // TODO: should be a category on NSCalendarDate +@@ -435,7 +340,8 @@ + for (pe = bytes; isalnum(*pe) || *pe == '-' || *pe == '+'; pe++) + ; + *pe = '\0'; +- if ((tz = parseTimeZone(bytes, (pe - bytes))) == nil) { ++ if (pe == bytes ++ || (tz = parseTimeZone((const char *) bytes, (pe - bytes))) == nil) { + [self logWithFormat: + @"WARNING: failed to parse RFC822 timezone: '%s' (value='%@')", + bytes, _data]; +@@ -444,9 +350,9 @@ + + /* construct and return */ + finished: +- date = [CalDateClass dateWithYear:year month:monthOfYear day:dayOfMonth +- hour:hour minute:minute second:second +- timeZone:tz]; ++ date = [NSCalendarDate dateWithYear:year month:monthOfYear day:dayOfMonth ++ hour:hour minute:minute second:second ++ timeZone:tz]; + if (date == nil) goto failed; + + #if 0 +Index: sope-mime/NGMime/NGMimeMultipartBodyParser.m +=================================================================== +--- sope-mime/NGMime/NGMimeMultipartBodyParser.m (revision 1664) ++++ sope-mime/NGMime/NGMimeMultipartBodyParser.m (working copy) +@@ -428,6 +428,7 @@ + NSString *boundary = nil; + NSArray *rawBodyParts = nil; + BOOL foundError = NO; ++ NSData *boundaryBytes; + + contentType = [_part contentType]; + boundary = [contentType valueOfParameter:@"boundary"]; +@@ -437,9 +438,10 @@ + + *(&foundError) = NO; + ++ boundaryBytes = [boundary dataUsingEncoding:NSISOLatin1StringEncoding]; + *(&rawBodyParts) = [self _parseBody:_body part:_part data:_data +- boundary:[boundary cString] +- length:[boundary cStringLength] ++ boundary:[boundaryBytes bytes] ++ length:[boundary length] + delegate:_d]; + + if (rawBodyParts) { +Index: sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m +=================================================================== +--- sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (revision 1664) ++++ sope-mime/NGMime/NGMimeHeaderFieldGeneratorSet.m (working copy) +@@ -77,6 +77,7 @@ + [rfc822Set setGenerator:gen forField:@"bcc"]; + [rfc822Set setGenerator:gen forField:Fields->from]; + [rfc822Set setGenerator:gen forField:@"reply-to"]; ++ [rfc822Set setGenerator:gen forField:@"in-reply-to"]; + [rfc822Set setGenerator:gen forField:@"Disposition-Notification-To"]; + } + +Index: sope-mime/NGMime/NGMimeType.m +=================================================================== +--- sope-mime/NGMime/NGMimeType.m (revision 1664) ++++ sope-mime/NGMime/NGMimeType.m (working copy) +@@ -120,30 +120,30 @@ + + /* some unsupported, but known encoding */ + else if ([charset isEqualToString:@"ks_c_5601-1987"]) { +- encoding = [NSString defaultCStringEncoding]; ++ encoding = NSISOLatin1StringEncoding; + foundUnsupported = YES; + } + else if ([charset isEqualToString:@"euc-kr"]) { +- encoding = [NSString defaultCStringEncoding]; +- foundUnsupported = YES; ++ encoding = NSKoreanEUCStringEncoding; + } + else if ([charset isEqualToString:@"big5"]) { +- encoding = [NSString defaultCStringEncoding]; +- foundUnsupported = YES; ++ encoding = NSBIG5StringEncoding; + } + else if ([charset isEqualToString:@"iso-2022-jp"]) { +- encoding = [NSString defaultCStringEncoding]; +- foundUnsupported = YES; ++ encoding = NSISO2022JPStringEncoding; + } + else if ([charset isEqualToString:@"gb2312"]) { +- encoding = [NSString defaultCStringEncoding]; +- foundUnsupported = YES; ++ encoding = NSGB2312StringEncoding; + } + else if ([charset isEqualToString:@"koi8-r"]) { +- encoding = [NSString defaultCStringEncoding]; +- foundUnsupported = YES; ++ encoding = NSKOI8RStringEncoding; + } +- ++ else if ([charset isEqualToString:@"windows-1250"]) { ++ encoding = NSWindowsCP1250StringEncoding; ++ } ++ else if ([charset isEqualToString:@"windows-1251"]) { ++ encoding = NSWindowsCP1251StringEncoding; ++ } + else if ([charset isEqualToString:@"windows-1252"]) { + encoding = NSWindowsCP1252StringEncoding; + } +@@ -152,7 +152,7 @@ + } + else if ([charset isEqualToString:@"x-unknown"] || + [charset isEqualToString:@"unknown"]) { +- encoding = NSASCIIStringEncoding; ++ encoding = NSISOLatin1StringEncoding; + } + /* ISO Latin 9 */ + #if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) +@@ -166,7 +166,7 @@ + else { + [self logWithFormat:@"%s: unknown charset '%@'", + __PRETTY_FUNCTION__, _s]; +- encoding = [NSString defaultCStringEncoding]; ++ encoding = NSISOLatin1StringEncoding; + } + return encoding; + } +@@ -385,23 +385,26 @@ + } + + - (BOOL)valueNeedsQuotes:(NSString *)_parameterValue { +- unsigned len = [_parameterValue cStringLength]; +- char buf[len + 15]; +- char *cstr; ++ NSData *stringData; ++ const char *cstr; ++ unsigned int count, max; ++ BOOL needsQuote; + +- cstr = &(buf[0]); ++ needsQuote = NO; + +- [_parameterValue getCString:cstr]; cstr[len] = '\0'; +- while (*cstr) { +- if (isMime_SpecialByte(*cstr)) +- return YES; ++ stringData = [_parameterValue dataUsingEncoding:NSUTF8StringEncoding]; ++ cstr = [stringData bytes]; ++ max = [stringData length]; ++ count = 0; ++ while (!needsQuote && count < max) { ++ if (isMime_SpecialByte(*(cstr + count)) ++ || *(cstr + count) == 32) ++ needsQuote = YES; ++ else ++ count++; ++ } + +- if (*cstr == 32) +- return YES; +- +- cstr++; +- } +- return NO; ++ return needsQuote; + } + + - (NSString *)stringValue { +Index: sope-mime/NGMime/NGMimeBodyPart.m +=================================================================== +--- sope-mime/NGMime/NGMimeBodyPart.m (revision 1664) ++++ sope-mime/NGMime/NGMimeBodyPart.m (working copy) +@@ -31,18 +31,6 @@ + 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]; + } +@@ -156,13 +144,12 @@ + 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 : (id)defaultType); ++ return type; + } + + - (NSString *)contentId { +Index: sope-mime/NGMime/ChangeLog +=================================================================== +--- sope-mime/NGMime/ChangeLog (revision 1664) ++++ sope-mime/NGMime/ChangeLog (working copy) +@@ -1,3 +1,25 @@ ++2008-09-08 Wolfgang Sourdeau ++ ++ * NGMimeRFC822DateHeaderFieldParser.m ([NGMimeRFC ++ -parseValue:ofHeaderField:]): don't parse timezone with a length ++ of 0. ++ ++2008-09-01 Wolfgang Sourdeau ++ ++ * NGMimeRFC822DateHeaderFieldParser.m ([NGMimeRFC ++ -parseValue:ofHeaderField:]): use an 8-bit safe encoding when ++ parsing dates. Since we only consider 7-bits characters, we ensure ++ that bad user-agents can be handled more properly. ++ ++ * NGMimeType.m ([NGMimeType +stringEncodingForCharset:]): ++ x-unknown encoding is now translated to an 8-bit safe encoding ++ (NSISOLatin1StringEncoding). ++ ++ * NGMimeAddressHeaderFieldGenerator.m ++ ([NGMimeAddressHeaderFieldGenerator ++ -generateDataForHeaderFieldNamed:value:]): encode resulting string ++ in an 8-bit safe encoding (NSISOLatin1StringEncoding). ++ + 2008-01-29 Albrecht Dress + + * fixes for OGo bug #789 (reply-to QP encoding) +Index: sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m +=================================================================== +--- sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (revision 1664) ++++ sope-mime/NGMime/NGMimeContentTypeHeaderFieldGenerator.m (working copy) +@@ -36,8 +36,7 @@ + NGMimeType *type = nil; // only one content-type field + NSString *tmp = nil; + NSMutableData *data = nil; +- unsigned char *ctmp = NULL; +- unsigned len = 0; ++ NSData *valueData; + + type = _value; + +@@ -59,21 +58,15 @@ + + tmp = [type type]; + NSAssert(tmp, @"type should not be nil"); +- len = [tmp length]; +- ctmp = malloc(len + 4); +- [tmp getCString:(char *)ctmp]; ctmp[len] = '\0'; +- [data appendBytes:ctmp length:len]; +- free(ctmp); ++ valueData = [tmp dataUsingEncoding: NSISOLatin1StringEncoding]; ++ [data appendData: valueData]; ++ ++ [data appendBytes:"/" length:1]; + +- [data appendBytes:"//" length:1]; +- + tmp = [type subType]; + if (tmp != nil) { +- len = [tmp length]; +- ctmp = malloc(len + 4); +- [tmp getCString:(char *)ctmp]; ctmp[len] = '\0'; +- [data appendBytes:ctmp length:len]; +- free(ctmp); ++ valueData = [tmp dataUsingEncoding: NSISOLatin1StringEncoding]; ++ [data appendData:valueData]; + } + else + [data appendBytes:"*" length:1]; +@@ -91,12 +84,9 @@ + continue; + } + [data appendBytes:"; " length:2]; +- +- len = [name cStringLength]; +- ctmp = malloc(len + 1); +- [name getCString:(char *)ctmp]; ctmp[len] = '\0'; +- [data appendBytes:ctmp length:len]; +- free(ctmp); ++ ++ valueData = [name dataUsingEncoding: NSUTF8StringEncoding]; ++ [data appendData: valueData]; + + /* + this confuses GroupWise: "= \"" (a space) +@@ -105,66 +95,30 @@ + + /* check for encoding */ + { +- unsigned cnt; ++ unsigned cnt, max; ++ const char *dataBytes; + BOOL doEnc; + +- len = [value cStringLength]; +- ctmp = malloc(len + 4); +- [value getCString:(char *)ctmp]; ctmp[len] = '\0'; +- cnt = 0; ++ valueData = [value dataUsingEncoding:NSUTF8StringEncoding]; ++ dataBytes = [valueData bytes]; ++ max = [valueData length]; ++ + doEnc = NO; +- while (cnt < len) { +- if ((unsigned char)ctmp[cnt] > 127) { ++ cnt = 0; ++ while (!doEnc && cnt < max) { ++ if ((unsigned char)dataBytes[cnt] > 127) + doEnc = YES; +- break; +- } +- cnt++; ++ else ++ 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 + 10); +- [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); ++ [data appendBytes:"=?utf-8?q?" length:10]; ++ [data appendData: [valueData dataByEncodingQuotedPrintable]]; ++ [data appendBytes:"?=" length:2]; + } + else { +- [data appendBytes:ctmp length:len]; ++ [data appendData: valueData]; + } +- free(ctmp); + } + [data appendBytes:"\"" length:1]; + } +Index: sope-mime/NGMime/NGMimePartGenerator.m +=================================================================== +--- sope-mime/NGMime/NGMimePartGenerator.m (revision 1664) ++++ sope-mime/NGMime/NGMimePartGenerator.m (working copy) +@@ -155,8 +155,9 @@ + BOOL isMultiValue, isFirst; + + /* get field name and strip leading spaces */ +- fcname = (const unsigned char *)[_field cString]; +- for (len = [_field cStringLength]; len > 0; fcname++, len--) { ++ fcname = (const unsigned char *)[_field cStringUsingEncoding:NSISOLatin1StringEncoding]; ++ for (len = [_field lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]; ++ len > 0; fcname++, len--) { + if (*fcname != ' ') + break; + } +@@ -328,7 +329,7 @@ + if ([body isKindOfClass:[NSData class]]) + data = body; + else if ([body isKindOfClass:[NSString class]]) +- data = [body dataUsingEncoding:[NSString defaultCStringEncoding]]; ++ data = [body dataUsingEncoding: NSISOLatin1StringEncoding]; + else + data = nil; + +Index: sope-mime/NGMime/NGMimeBodyParser.m +=================================================================== +--- sope-mime/NGMime/NGMimeBodyParser.m (revision 1664) ++++ sope-mime/NGMime/NGMimeBodyParser.m (working copy) +@@ -67,7 +67,10 @@ + if (_data == nil) return nil; + + ctype = [_part contentType]; +- ++ if (!ctype ++ && [_d respondsToSelector: @selector(parser:contentTypeOfPart:)]) ++ ctype = [_d parser: self contentTypeOfPart: _part]; ++ + if (![ctype isKindOfClass:[NGMimeType class]]) + ctype = [NGMimeType mimeType:[ctype stringValue]]; + +@@ -88,10 +91,20 @@ + NSStringEncoding encoding; + + encoding = [NGMimeType stringEncodingForCharset:charset]; +- ++ ++ // If we nave no encoding here, let's not simply return nil. ++ // We SHOULD try at least UTF-8 and after, Latin1. ++ if (!encoding) ++ encoding = NSUTF8StringEncoding; ++ + body = [[[NSString alloc] +- initWithData:_data ++ initWithData:_data + encoding:encoding] autorelease]; ++ ++ if (!body) ++ body = [[[NSString alloc] initWithData:_data ++ encoding:NSISOLatin1StringEncoding] ++ autorelease]; + } + return body; + } +Index: sope-mime/NGMime/NGMimePartParser.h +=================================================================== +--- sope-mime/NGMime/NGMimePartParser.h (revision 1664) ++++ sope-mime/NGMime/NGMimePartParser.h (working copy) +@@ -117,6 +117,7 @@ + BOOL parserParseRawBodyDataOfPart:1; + BOOL parserBodyParserForPart:1; + BOOL parserDecodeBodyOfPart:1; ++ BOOL parserContentTypeOfPart:1; + } delegateRespondsTo; + + +@@ -275,6 +276,9 @@ + - (id)parser:(NGMimePartParser *)_parser + bodyParserForPart:(id)_part; + ++- (NGMimeType *)parser:(id)_parser ++ contentTypeOfPart:(id)_part; ++ + @end /* NSObject(NGMimePartParserDelegate) */ + + @interface NSObject(NGMimePartParser) +Index: sope-mime/NGMime/NGMimePartParser.m +=================================================================== +--- sope-mime/NGMime/NGMimePartParser.m (revision 1664) ++++ sope-mime/NGMime/NGMimePartParser.m (working copy) +@@ -227,7 +227,7 @@ + } + + + (NSStringEncoding)defaultHeaderFieldEncoding { +- return NSISOLatin1StringEncoding; ++ return NSUTF8StringEncoding; + } + + - (id)valueOfHeaderField:(NSString *)_name data:(id)_data { +@@ -1091,7 +1091,10 @@ + id bodyParser = nil; + + ctype = [_p contentType]; +- ++ if (!ctype ++ && self->delegateRespondsTo.parserContentTypeOfPart) ++ ctype = [self->delegate parser: self contentTypeOfPart: _p]; ++ + contentType = ([ctype isKindOfClass:[NGMimeType class]]) + ? ctype + : [NGMimeType mimeType:[ctype stringValue]]; +Index: sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m +=================================================================== +--- sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (revision 1664) ++++ sope-mime/NGMime/NGMimeAddressHeaderFieldGenerator.m (working copy) +@@ -105,10 +105,10 @@ + } + + tmp = [obj displayName]; +- bufLen = [tmp cStringLength]; ++ bufLen = [tmp lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; + +- buffer = calloc(bufLen + 10, sizeof(char)); +- [tmp getCString:buffer]; ++ buffer = calloc(bufLen, sizeof(char)); ++ [tmp getCString: buffer maxLength: bufLen encoding: NSUTF8StringEncoding]; + + cnt = 0; + doEnc = NO; +@@ -117,11 +117,11 @@ + /* must encode chars outside ASCII 33..60, 62..126 ranges [RFC 2045, Sect. 6.7] + * RFC 2047, Sect. 4.2 also requires chars 63 and 95 to be encoded + * For spaces, quotation is fine */ +- if ((unsigned char)buffer[cnt] < 32 || +- (unsigned char)buffer[cnt] == 61 || +- (unsigned char)buffer[cnt] == 63 || +- (unsigned char)buffer[cnt] == 95 || +- (unsigned char)buffer[cnt] > 126) { ++ if ((unichar)buffer[cnt] < 32 || ++ (unichar)buffer[cnt] == 61 || ++ (unichar)buffer[cnt] == 63 || ++ (unichar)buffer[cnt] == 95 || ++ (unichar)buffer[cnt] > 126) { + doEnc = YES; + break; + } +@@ -130,8 +130,13 @@ + + if (doEnc) { + /* FIXME - better use UTF8 encoding! */ ++#if NeXT_Foundation_LIBRARY + unsigned char iso[] = "=?iso-8859-15?q?"; + unsigned isoLen = 16; ++#else ++ unsigned char iso[] = "=?utf-8?q?"; ++ unsigned isoLen = 10; ++#endif + unsigned char isoEnd[] = "?="; + unsigned isoEndLen = 2; + unsigned desLen; +@@ -141,10 +146,10 @@ + { + NSData *data; + +-#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY ++#if NeXT_Foundation_LIBRARY + data = [tmp dataUsingEncoding:NSISOLatin1StringEncoding]; + #else +- data = [tmp dataUsingEncoding:NSISOLatin9StringEncoding]; ++ data = [tmp dataUsingEncoding:NSUTF8StringEncoding]; + #endif + + bufLen = [data length]; +@@ -162,8 +167,9 @@ + des + isoLen, desLen - isoLen); + if ((int)desLen != -1) { + memcpy(des + isoLen + desLen, isoEnd, isoEndLen); +- tmp = [NSString stringWithCString:(char *)des +- length:(isoLen + desLen + isoEndLen)]; ++ tmp = [[NSString alloc] initWithData: [NSData dataWithBytes:(char *)des length:(isoLen + desLen + isoEndLen)] ++ encoding: NSISOLatin1StringEncoding]; ++ [tmp autorelease]; + } + else { + [self warnWithFormat: +@@ -190,11 +196,7 @@ + } + } + +-#if APPLE_Foundation_LIBRARY || NeXT_Foundation_LIBRARY + data = [result dataUsingEncoding:NSISOLatin1StringEncoding]; +-#else +- data = [result dataUsingEncoding:NSISOLatin9StringEncoding]; +-#endif + [result release]; + + return data; +Index: sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m +=================================================================== +--- sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (revision 1664) ++++ sope-mime/NGMime/NGMimeContentDispositionHeaderFieldGenerator.m (working copy) +@@ -49,80 +49,70 @@ + + // TODO: move the stuff below to some NSString or NSData category? + +- data = [NSMutableData dataWithCapacity:64]; ++ 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:(char *)ctmp]; ctmp[len] = '\0'; +- cnt = 0; +- doEnc = NO; +- while (cnt < len) { +- if ((unsigned char)ctmp[cnt] > 127) { +- doEnc = YES; +- break; +- } +- cnt++; ++ ++ NSData *d; ++ unsigned char* bytes; ++ unsigned length; ++ int cnt; ++ BOOL doEnc; ++ ++ //d = [tmp dataUsingEncoding: NSUTF8StringEncoding]; ++ //bytes = [d bytes]; ++ //length = [d length]; ++ bytes = [tmp cStringUsingEncoding: NSUTF8StringEncoding]; ++ length = strlen(bytes); ++ ++ cnt = 0; ++ doEnc = NO; ++ while (cnt < length) { ++ if ((unsigned char)bytes[cnt] > 127) { ++ doEnc = YES; ++ break; + } +- if (doEnc) { +- char iso[] = "=?iso-8859-15?q?"; +- unsigned isoLen = 16; +- char isoEnd[] = "?="; +- unsigned isoEndLen = 2; +- unsigned desLen; +- char *des; +- +- if (ctmp) free(ctmp); +- { +- NSData *data; ++ cnt++; ++ } + +-#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((unsigned char *)ctmp + cnt, len - cnt, +- (unsigned char *)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 { ++ if (doEnc) ++ { ++ char iso[] = "=?utf-8?q?"; ++ unsigned isoLen = 10; ++ char isoEnd[] = "?="; ++ unsigned isoEndLen = 2; ++ int desLen; ++ char *des; ++ ++ desLen = length * 3 + 20; ++ ++ des = calloc(desLen + 2, sizeof(char)); ++ ++ memcpy(des, iso, isoLen); ++ desLen = NGEncodeQuotedPrintableMime((unsigned char *)bytes, length, ++ (unsigned char *)(des + isoLen), ++ desLen - isoLen); ++ if (desLen != -1) { ++ memcpy(des + isoLen + desLen, isoEnd, isoEndLen); ++ [data appendBytes:des length:(isoLen + desLen + isoEndLen)]; ++ } ++ else { + [self logWithFormat:@"WARNING(%s:%i): An error occour during " + @"quoted-printable decoding", + __PRETTY_FUNCTION__, __LINE__]; +- } +- if (des) free(des); ++ if (des != NULL) free(des); ++ } + } +- else { +- [data appendBytes:ctmp length:len]; ++ else ++ { ++ [data appendBytes:[tmp cString] length:[tmp length]]; + } +- } +- // [data appendBytes:[tmp cString] length:[tmp length]]; +- [data appendBytes:"\"" length:1]; ++ ++ [data appendBytes:"\"" length:1]; + } + return data; + } +Index: sope-core/NGExtensions/NGExtensions/NSString+Ext.h +=================================================================== +--- sope-core/NGExtensions/NGExtensions/NSString+Ext.h (revision 1664) ++++ sope-core/NGExtensions/NGExtensions/NSString+Ext.h (working copy) +@@ -30,6 +30,7 @@ + + @interface NSString(GSAdditions) + ++#if !GNUSTEP + - (NSString *)stringWithoutPrefix:(NSString *)_prefix; + - (NSString *)stringWithoutSuffix:(NSString *)_suffix; + +@@ -39,6 +40,7 @@ + - (NSString *)stringByTrimmingLeadSpaces; + - (NSString *)stringByTrimmingTailSpaces; + - (NSString *)stringByTrimmingSpaces; ++#endif /* !GNUSTEP */ + + /* the following are not available in gstep-base 1.6 ? */ + - (NSString *)stringByTrimmingLeadWhiteSpaces; +@@ -47,6 +49,8 @@ + + @end /* NSString(GSAdditions) */ + ++#if !GNUSTEP ++ + @interface NSMutableString(GNUstepCompatibility) + + - (void)trimLeadSpaces; +@@ -55,6 +59,8 @@ + + @end /* NSMutableString(GNUstepCompatibility) */ + ++#endif /* !GNUSTEP */ ++ + #endif + + /* specific to libFoundation */ +Index: sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m +=================================================================== +--- sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (revision 1664) ++++ sope-core/NGExtensions/FdExt.subproj/NSString+Ext.m (working copy) +@@ -39,18 +39,6 @@ + : (NSString *)[[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' .. +@@ -96,6 +84,25 @@ + return [[self copy] autorelease]; + } + ++- (NSString *)stringByTrimmingWhiteSpaces ++{ ++ return [[self stringByTrimmingTailWhiteSpaces] ++ stringByTrimmingLeadWhiteSpaces]; ++} ++ ++#ifndef GNUSTEP ++- (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 *)stringByTrimmingLeadSpaces + { + unsigned len; +@@ -117,6 +124,7 @@ + else + return [[self copy] autorelease]; + } ++ + - (NSString *)stringByTrimmingTailSpaces + { + unsigned len; +@@ -139,19 +147,17 @@ + return [[self copy] autorelease]; + } + +-- (NSString *)stringByTrimmingWhiteSpaces +-{ +- return [[self stringByTrimmingTailWhiteSpaces] +- stringByTrimmingLeadWhiteSpaces]; +-} + - (NSString *)stringByTrimmingSpaces + { + return [[self stringByTrimmingTailSpaces] + stringByTrimmingLeadSpaces]; + } ++#endif + + @end /* NSString(GSAdditions) */ + ++#if !GNUSTEP ++ + @implementation NSMutableString(GNUstepCompatibility) + + - (void)trimLeadSpaces +@@ -169,6 +175,8 @@ + + @end /* NSMutableString(GNUstepCompatibility) */ + ++#endif /* !GNUSTEP */ ++ + @implementation NSString(lfNSURLUtilities) + + - (BOOL)isAbsoluteURL +Index: sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m +=================================================================== +--- sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (revision 1664) ++++ sope-core/NGExtensions/FdExt.subproj/NSString+Encoding.m (working copy) +@@ -140,8 +140,12 @@ + + + #ifdef __linux__ ++#if __BYTE_ORDER == __LITTLE_ENDIAN + static NSString *unicharEncoding = @"UCS-2LE"; + #else ++static NSString *unicharEncoding = @"UCS-2BE"; ++#endif /* __BYTE_ORDER */ ++#else + static NSString *unicharEncoding = @"UCS-2-INTERNAL"; + #endif + static int IconvLogEnabled = -1; +@@ -149,21 +153,12 @@ + static void checkDefaults(void) { + NSUserDefaults *ud; + +- if (IconvLogEnabled != -1) +- return; +- ud = [NSUserDefaults standardUserDefaults]; +- IconvLogEnabled = [ud boolForKey:@"IconvLogEnabled"]?1:0; ++ if (IconvLogEnabled == -1) { ++ 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"; ++ NSLog(@"Note: using '%@' on Linux.", unicharEncoding); + } +- else { +- NSLog(@"Note: using UCS-2 little endian on Linux."); +- unicharEncoding = @"UCS-2LE"; +- } +-#endif + } + + static char *iconv_wrapper(id self, char *_src, unsigned _srcLen, +Index: sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m +=================================================================== +--- sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (revision 1664) ++++ sope-core/NGExtensions/EOExt.subproj/EOGlobalID+Ext.m (working copy) +@@ -19,6 +19,7 @@ + 02111-1307, USA. + */ + ++#import + #import + #import + +Index: sope-core/NGStreams/NGStream+serialization.m +=================================================================== +--- sope-core/NGStreams/NGStream+serialization.m (revision 1664) ++++ sope-core/NGStreams/NGStream+serialization.m (working copy) +@@ -282,10 +282,10 @@ + else { + char *result = NULL; + +-#if NeXT_Foundation_LIBRARY ++#if LIB_FOUNDATION_LIBRARY ++ result = NSZoneMallocAtomic(NULL, len + 1); ++#else + result = NSZoneMalloc(NULL, len + 1); +-#else +- result = NSZoneMallocAtomic(NULL, len + 1); + #endif + result[len] = '\0'; + +Index: sope-core/NGStreams/NGStreams/NGDatagramSocket.h +=================================================================== +--- sope-core/NGStreams/NGStreams/NGDatagramSocket.h (revision 1664) ++++ sope-core/NGStreams/NGStreams/NGDatagramSocket.h (working copy) +@@ -69,7 +69,7 @@ + + (id)socketBoundToAddress:(id)_address; + + #if !defined(WIN32) +-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain; +++ (BOOL)socketPair:(id[2])_pair; + #endif + + // accessors +Index: sope-core/NGStreams/NGStreams/NGActiveSocket.h +=================================================================== +--- sope-core/NGStreams/NGStreams/NGActiveSocket.h (revision 1664) ++++ sope-core/NGStreams/NGStreams/NGActiveSocket.h (working copy) +@@ -60,7 +60,7 @@ + - (id)initWithDomain:(id)_domain; // designated initializer + + #if !defined(WIN32) +-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain; +++ (BOOL)socketPair:(id[2])_pair; + #endif + + // ******************** operations ******************** +Index: sope-core/NGStreams/NGGZipStream.m +=================================================================== +--- sope-core/NGStreams/NGGZipStream.m (revision 1664) ++++ sope-core/NGStreams/NGGZipStream.m (working copy) +@@ -52,7 +52,7 @@ + @"invalid compression level %i (0-9)", _level); + + self->outBufLen = 2048; +-#if GNU_RUNTIME ++#if LIB_FOUNDATION_LIBRARY + self->outBuf = NSZoneMallocAtomic([self zone], self->outBufLen); + self->outp = NSZoneMallocAtomic([self zone], sizeof(z_stream)); + #else +Index: sope-core/NGStreams/NGDatagramSocket.m +=================================================================== +--- sope-core/NGStreams/NGDatagramSocket.m (revision 1664) ++++ sope-core/NGStreams/NGDatagramSocket.m (working copy) +@@ -25,6 +25,8 @@ + #endif + + #include ++#include ++#include + #include "NGDatagramSocket.h" + #include "NGDatagramPacket.h" + #include "NGSocketExceptions.h" +@@ -55,19 +57,21 @@ + + #if !defined(WIN32) || defined(__CYGWIN32__) + +-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain { +++ (BOOL)socketPair:(id[2])_pair { + int fds[2]; ++ NGLocalSocketDomain *domain; + + _pair[0] = nil; + _pair[1] = nil; + +- if (socketpair([_domain socketDomain], SOCK_DGRAM, [_domain protocol], ++ domain = [NGLocalSocketDomain domain]; ++ 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 = [[self alloc] _initWithDomain:domain descriptor:fds[0]]; ++ s2 = [[self alloc] _initWithDomain:domain descriptor:fds[1]]; + s1 = AUTORELEASE(s1); + s2 = AUTORELEASE(s2); + +@@ -112,7 +116,7 @@ + break; + } + [[[NGCouldNotCreateSocketException alloc] +- initWithReason:reason domain:_domain] raise]; ++ initWithReason:reason domain:domain] raise]; + return NO; + } + } +Index: sope-core/NGStreams/GNUmakefile.preamble +=================================================================== +--- sope-core/NGStreams/GNUmakefile.preamble (revision 1664) ++++ sope-core/NGStreams/GNUmakefile.preamble (working copy) +@@ -1,6 +1,7 @@ + # compilation settings + +-MACHCPU = $(shell echo $$MACHTYPE | cut -f 1 -d '-') ++# MACHCPU = $(shell echo $$MACHTYPE | cut -f 1 -d '-') ++MACHCPU = $(shell uname -m) + + libNGStreams_INCLUDE_DIRS += \ + -I$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS) \ +Index: sope-core/NGStreams/ChangeLog +=================================================================== +--- sope-core/NGStreams/ChangeLog (revision 1664) ++++ sope-core/NGStreams/ChangeLog (working copy) +@@ -1,3 +1,14 @@ ++2009-11-11 Wolfgang Sourdeau ++ ++ * NGActiveSocket.m (+socketPair): removed the domain: parameter as ++ only AF_LOCAL is permitted. Assign a default instance of ++ NGLocalSocketAddress to the sockets to "declare" the sockets as ++ connected. ++ ++ * NGActiveSocket.m (-setSendTimeout, -setReceiveTimeout): make use ++ of those methods to actually configure the timeouts on the socket ++ objects (via setsockopt and SO_RCVTIMEO and SO_SNDTIMEO). ++ + 2009-03-24 Wolfgang Sourdeau + + * GNUmakefile.preamble: add machine-type to include path (eg i386) (v4.7.57) +Index: sope-core/NGStreams/NGCharBuffer.m +=================================================================== +--- sope-core/NGStreams/NGCharBuffer.m (revision 1664) ++++ sope-core/NGStreams/NGCharBuffer.m (working copy) +@@ -46,11 +46,11 @@ + // 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 ++#if LIB_FOUNDATION_LIBRARY + self->la = NSZoneMallocAtomic([self zone], + sizeof(LA_NGCharBuffer) * size); ++#else ++ self->la = NSZoneMalloc([self zone], sizeof(LA_NGCharBuffer) * size); + #endif + memset(self->la, 0, sizeof(LA_NGCharBuffer) * size); + +Index: sope-core/NGStreams/NGActiveSocket.m +=================================================================== +--- sope-core/NGStreams/NGActiveSocket.m (revision 1664) ++++ sope-core/NGStreams/NGActiveSocket.m (working copy) +@@ -62,6 +62,8 @@ + #include "common.h" + + #include ++#include ++#include + #include "NGActiveSocket.h" + #include "NGSocketExceptions.h" + #include "NGSocket+private.h" +@@ -83,29 +85,35 @@ + + #if !defined(WIN32) || defined(__CYGWIN32__) + +-+ (BOOL)socketPair:(id[2])_pair inDomain:(id)_domain { +++ (BOOL)socketPair:(id[2])_pair { + int fds[2]; ++ NGLocalSocketDomain *domain; + + _pair[0] = nil; + _pair[1] = nil; + +- if (socketpair([_domain socketDomain], SOCK_STREAM, [_domain protocol], ++ domain = [NGLocalSocketDomain domain]; ++ if (socketpair([domain socketDomain], SOCK_STREAM, [domain protocol], + fds) == 0) { + NGActiveSocket *s1 = nil; + NGActiveSocket *s2 = nil; ++ NGLocalSocketAddress *address; + +- s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]]; +- s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]]; ++ s1 = [[self alloc] _initWithDomain:domain descriptor:fds[0]]; ++ s2 = [[self alloc] _initWithDomain:domain descriptor:fds[1]]; + s1 = [s1 autorelease]; + s2 = [s2 autorelease]; + ++ address = [NGLocalSocketAddress address]; + if ((s1 != nil) && (s2 != nil)) { + s1->mode = NGStreamMode_readWrite; + s1->receiveTimeout = 0.0; + s1->sendTimeout = 0.0; ++ ASSIGN(s1->remoteAddress, address); + s2->mode = NGStreamMode_readWrite; + s2->receiveTimeout = 0.0; + s2->sendTimeout = 0.0; ++ ASSIGN(s2->remoteAddress, address); + + _pair[0] = s1; + _pair[1] = s2; +@@ -152,7 +160,7 @@ + break; + } + [[[NGCouldNotCreateSocketException alloc] +- initWithReason:reason domain:_domain] raise]; ++ initWithReason:reason domain:domain] raise]; + return NO; + } + } +@@ -507,6 +515,13 @@ + } + + - (void)setSendTimeout:(NSTimeInterval)_timeout { ++ struct timeval tv; ++ ++ if ([self isConnected]) { ++ tv.tv_sec = (int) _timeout; ++ tv.tv_usec = 0; ++ setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (struct timeval)); ++ } + self->sendTimeout = _timeout; + } + - (NSTimeInterval)sendTimeout { +@@ -514,6 +529,13 @@ + } + + - (void)setReceiveTimeout:(NSTimeInterval)_timeout { ++ struct timeval tv; ++ ++ if ([self isConnected]) { ++ tv.tv_sec = (int) _timeout; ++ tv.tv_usec = 0; ++ setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (struct timeval)); ++ } + self->receiveTimeout = _timeout; + } + - (NSTimeInterval)receiveTimeout { +Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h +=================================================================== +--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (revision 1664) ++++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.h (working copy) +@@ -19,6 +19,8 @@ + 02111-1307, USA. + */ + ++#include ++ + #include + #include + #include +@@ -34,7 +36,7 @@ + + @interface libxmlHTMLSAXDriver : NSObject < SaxXMLReader > + { +- id contentHandler; ++ NSObject *contentHandler; + id dtdHandler; + id errorHandler; + id entityResolver; +Index: sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m +=================================================================== +--- sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (revision 1664) ++++ sope-xml/libxmlSAXDriver/libxmlHTMLSAXDriver.m (working copy) +@@ -200,10 +200,10 @@ + return self->entityResolver; + } + +-- (void)setContentHandler:(id)_handler { ++- (void)setContentHandler:(NSObject *)_handler { + ASSIGN(self->contentHandler, _handler); + } +-- (id)contentHandler { ++- (NSObject *)contentHandler { + return self->contentHandler; + } + +Index: sope-appserver/mod_ngobjweb/GNUmakefile +=================================================================== +--- sope-appserver/mod_ngobjweb/GNUmakefile (revision 1664) ++++ sope-appserver/mod_ngobjweb/GNUmakefile (working copy) +@@ -82,7 +82,7 @@ + + CFLAGS = -Wall -I. -fPIC \ + $(APXS_CFLAGS) $(APR_CFLAGS) \ +- $(APXS_INCLUDE_DIRS) $(APR_INCLUDE_DIRS) ++ $(APXS_INCLUDE_DIRS) $(APR_INCLUDE_DIRS) -O0 -ggdb + + LDFLAGS = $(APXS_LDFLAGS) $(APR_LDFLAGS) -shared -fPIC + LDLIBS = $(APXS_LIBS) $(APR_LIBS) +@@ -111,8 +111,7 @@ + apache-dir : + $(MKDIRS) $(GNUSTEP_INSTALLATION_DIR) + +-install :: apache-dir all +- $(INSTALL_PROGRAM) $(product) $(GNUSTEP_INSTALLATION_DIR) ++install :: + + install-usr-libexec :: all + $(INSTALL_PROGRAM) $(product) /usr/libexec/httpd/ +Index: sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m +=================================================================== +--- sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOWatchDogApplicationMain.m (working copy) +@@ -1,5 +1,6 @@ + /* + Copyright (C) 2000-2005 SKYRIX Software AG ++ Copyright (C) 2009 Inverse inc. + + This file is part of SOPE. + +@@ -19,9 +20,29 @@ + 02111-1307, USA. + */ + +-#import +-#include ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import + ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++#import ++ ++#import "UnixSignalHandler.h" ++ + #if defined(__CYGWIN32__) || defined(__MINGW32__) + + int WOWatchDogApplicationMain +@@ -39,201 +60,911 @@ + #include + #include + +-static pid_t child = -1; +-static NSString *pidFile = nil; +-static time_t lastFailExit = 0; +-static unsigned failExitCount = 0; +-static BOOL killedChild = NO; ++static NSTimeInterval respawnDelay; /* seconds */ ++static const char *pidFile = NULL; + +-static void killChild(void) { +- if (child > 0) { +- int status; +- +- fprintf(stderr, "watchdog[%i]: terminating child %i ..\n", getpid(), child); +- +- if (kill(child, SIGTERM) == 0) { +- waitpid(child, &status, 0); +- killedChild = YES; +- +- fprintf(stderr, " terminated child %i", child); +- +- if (WIFEXITED(status)) +- fprintf(stderr, " exit=%i", WEXITSTATUS(status)); +- if (WIFSIGNALED(status)) +- fprintf(stderr, " signal=%i", WTERMSIG(status)); +- +- fprintf(stderr, ".\n"); +- fflush(stderr); +- +- child = -1; +- return; ++typedef enum { ++ WOChildStatusDown = 0, ++ WOChildStatusSpawning, ++ WOChildStatusReady, ++ WOChildStatusBusy, ++ WOChildStatusExcessive, ++ WOChildStatusTerminating, ++ WOChildStatusMax ++} WOChildStatus; ++ ++@class WOWatchDog; ++ ++@interface WOWatchDogChild : NSObject ++{ ++ int pid; ++ int SIGCHLDStatus; ++ int counter; ++ NGActiveSocket *controlSocket; ++ WOChildStatus status; ++ WOWatchDog *watchDog; ++ NSCalendarDate *lastSpawn; ++ BOOL loggedNotRespawn; ++} ++ ++- (void) setWatchDog: (WOWatchDog *) newWatchDog; ++ ++- (void) setPid: (int) newPid; ++- (int) pid; ++ ++- (void) setSIGCHLDStatus: (int) newSIGCHLDStatus; ++- (int) SIGCHLDStatus; ++- (void) handleSIGCHLDStatus; ++ ++- (void) setControlSocket: (NGActiveSocket *) newSocket; ++- (NGActiveSocket *) controlSocket; ++ ++- (void) setStatus: (WOChildStatus) newStatus; ++- (WOChildStatus) status; ++ ++- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn; ++- (NSCalendarDate *) lastSpawn; ++- (NSCalendarDate *) nextSpawn; ++- (void) logNotRespawn; ++ ++- (BOOL) readMessage; ++ ++- (void) notify; ++- (void) terminate; ++ ++@end ++ ++@interface WOWatchDog : NSObject ++{ ++ NSString *appName; ++ int argc; ++ const char **argv; ++ ++ BOOL terminate; ++ BOOL willTerminate; ++ NSNumber *terminationSignal; ++ int pendingSIGCHLD; ++ int pendingSIGHUP; ++ ++ NGPassiveSocket *listeningSocket; ++ ++ int numberOfChildren; ++ NSMutableArray *children; ++ NSMutableArray *readyChildren; ++ NSMutableArray *downChildren; ++} ++ +++ (id) sharedWatchDog; ++ ++- (void) declareChildReady: (WOWatchDogChild *) readyChild; ++- (void) declareChildDown: (WOWatchDogChild *) readyChild; ++ ++- (int) run: (NSString *) appName ++ argc: (int) argc ++ argv: (const char **) argv; ++ ++@end ++ ++@implementation WOWatchDogChild ++ +++ (WOWatchDogChild *) watchDogChild ++{ ++ WOWatchDogChild *newChild; ++ ++ newChild = [self new]; ++ [newChild autorelease]; ++ ++ return newChild; ++} ++ ++- (id) init ++{ ++ if ((self = [super init])) ++ { ++ pid = -1; ++ controlSocket = nil; ++ SIGCHLDStatus = -1; ++ status = WOChildStatusDown; ++ counter = 0; ++ lastSpawn = nil; ++ loggedNotRespawn = NO; + } +- else if (kill(child, SIGKILL)) { +- waitpid(child, &status, 0); +- killedChild = YES; +- +- fprintf(stderr, " killed child %i", child); +- +- if (WIFEXITED(status)) +- fprintf(stderr, " exit=%i", WEXITSTATUS(status)); +- if (WIFSIGNALED(status)) +- fprintf(stderr, " signal=%i", WTERMSIG(status)); +- +- fprintf(stderr, ".\n"); +- fflush(stderr); +- +- child = -1; +- return; ++ ++ return self; ++} ++ ++- (void) dealloc ++{ ++ [self setControlSocket: nil]; ++ [lastSpawn release]; ++ [super dealloc]; ++} ++ ++- (void) setWatchDog: (WOWatchDog *) newWatchDog ++{ ++ watchDog = newWatchDog; ++} ++ ++- (void) setPid: (int) newPid ++{ ++ pid = newPid; ++} ++ ++- (int) pid ++{ ++ return pid; ++} ++ ++- (void) setSIGCHLDStatus: (int) newSIGCHLDStatus ++{ ++ SIGCHLDStatus = newSIGCHLDStatus; ++} ++ ++- (int) SIGCHLDStatus ++{ ++ return SIGCHLDStatus; ++} ++ ++- (void) handleSIGCHLDStatus ++{ ++ int code; ++ ++ [self logWithFormat: @"received SIGCHLD from pid %d", pid]; ++ code = WEXITSTATUS (SIGCHLDStatus); ++ if (code != 0) ++ [self logWithFormat: @"child %d exited with code %i", pid, code]; ++ if (WIFSIGNALED (SIGCHLDStatus)) ++ [self logWithFormat: @" (terminated due to signal %i%@)", ++ WTERMSIG (SIGCHLDStatus), ++ WCOREDUMP (SIGCHLDStatus) ? @", coredump" : @""]; ++ if (WIFSTOPPED (SIGCHLDStatus)) ++ [self logWithFormat: @" (stopped due to signal %i)", WSTOPSIG (SIGCHLDStatus)]; ++ SIGCHLDStatus = -1; ++ [self setStatus: WOChildStatusDown]; ++ [self setControlSocket: nil]; ++} ++ ++- (void) setControlSocket: (NGActiveSocket *) newSocket ++{ ++ NSRunLoop *runLoop; ++ ++ runLoop = [NSRunLoop currentRunLoop]; ++ if (controlSocket) ++ [runLoop removeEvent: (void *) [controlSocket fileDescriptor] ++ type: ET_RDESC ++ forMode: NSDefaultRunLoopMode ++ all: YES]; ++ [controlSocket close]; ++ ASSIGN (controlSocket, newSocket); ++ if (controlSocket) ++ [runLoop addEvent: (void *) [controlSocket fileDescriptor] ++ type: ET_RDESC ++ watcher: self ++ forMode: NSDefaultRunLoopMode]; ++} ++ ++- (NGActiveSocket *) controlSocket ++{ ++ return controlSocket; ++} ++ ++- (void) setStatus: (WOChildStatus) newStatus ++{ ++ status = newStatus; ++} ++ ++- (WOChildStatus) status ++{ ++ return status; ++} ++ ++- (void) setLastSpawn: (NSCalendarDate *) newLastSpawn ++{ ++ ASSIGN (lastSpawn, newLastSpawn); ++ loggedNotRespawn = NO; ++} ++ ++- (NSCalendarDate *) lastSpawn ++{ ++ return lastSpawn; ++} ++ ++- (NSCalendarDate *) nextSpawn ++{ ++ return [lastSpawn addYear: 0 month: 0 day: 0 ++ hour: 0 minute: 0 ++ second: respawnDelay]; ++} ++ ++- (void) logNotRespawn ++{ ++ if (!loggedNotRespawn) ++ { ++ [self logWithFormat: ++ @"avoiding to respawn child before %@", [self nextSpawn]]; ++ loggedNotRespawn = YES; + } ++} ++ ++- (BOOL) readMessage ++{ ++ WOChildMessage message; ++ BOOL rc; ++ ++ if ([controlSocket readBytes: &message ++ count: sizeof (WOChildMessage)] == NGStreamError) { ++ rc = NO; ++ [self errorWithFormat: @"FAILURE receiving status for child %d", pid]; ++ [self errorWithFormat: @" socket: %@", controlSocket]; + } ++ else { ++ rc = YES; ++ if (message == WOChildMessageAccept) { ++ status = WOChildStatusBusy; ++ } ++ else if (message == WOChildMessageReady) { ++ status = WOChildStatusReady; ++ [watchDog declareChildReady: self]; ++ } ++ // else if (message == WOChildMessageShutdown) { ++ // status = WOChildStatusDown; ++ // [watchDog declareChildDown: self]; ++ // } ++ // [self logStatus]; ++ } ++ ++ return rc; + } + +-static void _writePid(NSString *pidFile) { +- if ([pidFile length] > 0) { +- FILE *pf; +- +- if ((pf = fopen([pidFile cString], "w"))) { +- fprintf(pf, "%i\n", getpid()); +- fflush(pf); +- fclose(pf); ++- (BOOL) _sendMessage: (WOChildMessage) message ++{ ++ return ([controlSocket writeBytes: &message ++ count: sizeof (WOChildMessage)] != NGStreamError ++ && [self readMessage]); ++} ++ ++- (void) _killKill ++{ ++ if (status != WOChildStatusDown) { ++ [self warnWithFormat: @"sending KILL signal to pid %d", pid]; ++ kill (pid, SIGKILL); ++ } ++} ++ ++- (void) _kill ++{ ++ if (status != WOChildStatusDown) { ++ [self logWithFormat: @"sending terminate signal to pid %d", pid]; ++ status = WOChildStatusTerminating; ++ kill (pid, SIGTERM); ++ /* We hardcode a 5 minutes delay before ensuring that all children are ++ terminated. This enables long requests to finish properly while ++ avoiding 100% CPU usage for deadlocked children. */ ++ [NSTimer scheduledTimerWithTimeInterval: 5.0 * 60 ++ target: self ++ selector: @selector (_killKill) ++ userInfo: nil ++ repeats: NO]; ++ } ++} ++ ++- (void) notify ++{ ++ WOChildMessage message; ++ ++ counter++; ++ message = WOChildMessageAccept; ++ if (![self _sendMessage: message]) { ++ [self errorWithFormat: @"FAILURE notifying child %d", pid]; ++ [self _kill]; ++ } ++} ++ ++- (void) terminate ++{ ++ if (status == WOChildStatusDown) { ++ [self logWithFormat: @"child is already down"]; ++ } else { ++ [self setControlSocket: nil]; ++ [self _kill]; ++ } ++} ++ ++- (void) receivedEvent: (void*)data ++ type: (RunLoopEventType)type ++ extra: (void*)extra ++ forMode: (NSString*)mode ++{ ++ if ([controlSocket isAlive]) ++ [self readMessage]; ++ else { ++ /* This happens when a socket has been closed by the child but the child ++ has not terminated yet. */ ++ [[NSRunLoop currentRunLoop] removeEvent: data ++ type: ET_RDESC ++ forMode: NSDefaultRunLoopMode ++ all: YES]; ++ [self setControlSocket: nil]; ++ } ++} ++ ++@end ++ ++@implementation WOWatchDog ++ +++ (id) sharedWatchDog ++{ ++ static WOWatchDog *sharedWatchDog = nil; ++ ++ if (!sharedWatchDog) ++ sharedWatchDog = [self new]; ++ ++ return sharedWatchDog; ++} ++ ++- (id) init ++{ ++ if ((self = [super init])) ++ { ++ listeningSocket = nil; ++ terminate = NO; ++ willTerminate = NO; ++ terminationSignal = nil; ++ pendingSIGCHLD = 0; ++ pendingSIGHUP = 0; ++ ++ numberOfChildren = 0; ++ children = [[NSMutableArray alloc] initWithCapacity: 10]; ++ readyChildren = [[NSMutableArray alloc] initWithCapacity: 10]; ++ downChildren = [[NSMutableArray alloc] initWithCapacity: 10]; + } ++ ++ return self; ++} ++ ++- (void) _releaseListeningSocket ++{ ++ if (listeningSocket) { ++ [[NSRunLoop currentRunLoop] removeEvent: (void *) [listeningSocket fileDescriptor] ++ type: ET_RDESC ++ forMode: NSDefaultRunLoopMode ++ all: YES]; ++ [listeningSocket close]; ++ [listeningSocket release]; ++ listeningSocket = nil; + } + } +-static void _delPid(void) { +- if ([pidFile length] > 0) { +- if (unlink([pidFile cString]) == 0) +- pidFile = nil; ++ ++- (void) dealloc ++{ ++ [self _releaseListeningSocket]; ++ [terminationSignal release]; ++ [appName release]; ++ [children release]; ++ [super dealloc]; ++} ++ ++- (void) _runChildWithControlSocket: (NGActiveSocket *) controlSocket ++{ ++ WOApplication *app; ++ extern char **environ; ++ ++ [NSProcessInfo initializeWithArguments: (char **) argv ++ count: argc ++ environment: environ]; ++ NGInitTextStdio(); ++ app = [NSClassFromString(appName) new]; ++ [app autorelease]; ++ [app setListeningSocket: listeningSocket]; ++ [app setControlSocket: controlSocket]; ++ [app run]; ++} ++ ++- (void) receivedEvent: (void*)data ++ type: (RunLoopEventType)type ++ extra: (void*)extra ++ forMode: (NSString*)mode ++{ ++ int nextId; ++ WOWatchDogChild *child; ++ ++ // NSLog (@"have a child accept the connection"); ++ nextId = [readyChildren count] - 1; ++ if (nextId > -1) ++ { ++ child = [readyChildren objectAtIndex: nextId]; ++ [readyChildren removeObjectAtIndex: nextId]; ++ [child notify]; ++ } ++ // else ++ // NSLog (@"all children busy"); ++} ++ ++- (void) _cleanupSignalAndEventHandlers ++{ ++ int count; ++ NSRunLoop *runLoop; ++ ++ [[UnixSignalHandler sharedHandler] removeObserver: self]; ++ ++ runLoop = [NSRunLoop currentRunLoop]; ++ [runLoop removeEvent: (void *) [listeningSocket fileDescriptor] ++ type: ET_RDESC ++ forMode: NSDefaultRunLoopMode ++ all: YES]; ++ ++ for (count = 0; count < numberOfChildren; count++) { ++ [[children objectAtIndex: count] setControlSocket: nil]; ++ // controlSocket = [[children objectAtIndex: count] controlSocket]; ++ // if (controlSocket) ++ // [runLoop removeEvent: (void *) [controlSocket fileDescriptor] ++ // type: ET_RDESC ++ // forMode: NSDefaultRunLoopMode ++ // all: YES]; + } + } + +-static void exitWatchdog(void) { +- killChild(); +- _delPid(); ++- (BOOL) _spawnChild: (WOWatchDogChild *) child ++{ ++ NGActiveSocket *pair[2]; ++ BOOL isChild; ++ int childPid; ++ extern char **environ; ++ ++ isChild = NO; ++ ++ if ([NGActiveSocket socketPair: pair]) { ++ childPid = fork (); ++ if (childPid == 0) { ++ setsid (); ++ isChild = YES; ++ [self _cleanupSignalAndEventHandlers]; ++ [self _runChildWithControlSocket: pair[0]]; ++ } else if (childPid > 0) { ++ [self logWithFormat: @"child spawned with pid %d", childPid]; ++ [child setPid: childPid]; ++ [child setStatus: WOChildStatusSpawning]; ++ [child setControlSocket: pair[1]]; ++ [child setLastSpawn: [NSCalendarDate date]]; ++ // [self logWithFormat: @"parent ready for child: %d", childPid]; ++ } else { ++ perror ("fork"); ++ } ++ } ++ ++ return isChild; + } + +-static void wsignalHandler(int _signal) { +- switch (_signal) { +- case SIGINT: +- /* Control-C */ +- fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid()); +- killChild(); +- exit(0); +- /* shouldn't get here */ +- abort(); ++- (void) _ensureNumberOfChildren ++{ ++ int currentNumber, delta, count, min, max; ++ WOWatchDogChild *child; + +- case SIGSEGV: +- /* Coredump ! */ +- fprintf(stderr, +- "[%i]: watchdog handling segmentation fault " +- "(SERIOUS PROBLEM) ..\n", +- getpid()); +- killChild(); +- exit(123); +- /* shouldn't get here */ +- abort(); ++ currentNumber = [children count]; ++ if (currentNumber < numberOfChildren) { ++ delta = numberOfChildren - currentNumber; ++ for (count = 0; count < delta; count++) { ++ child = [WOWatchDogChild watchDogChild]; ++ [child setWatchDog: self]; ++ [children addObject: child]; ++ [downChildren addObject: child]; ++ } ++ [self logWithFormat: @"preparing %d children", delta]; ++ } ++ else if (currentNumber > numberOfChildren) { ++ delta = currentNumber - numberOfChildren; ++ max = [downChildren count]; ++ if (max > delta) ++ min = max - delta; ++ else ++ min = 0; ++ for (count = max - 1; count >= min; count--) { ++ child = [downChildren objectAtIndex: count]; ++ [downChildren removeObjectAtIndex: count]; ++ [children removeObject: child]; ++ delta--; ++ [self logWithFormat: @"%d processes purged from pool", delta]; ++ } + +- case SIGTERM: +- /* TERM signal (kill 'pid') */ +- fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid()); +- killChild(); +- exit(0); +- /* shouldn't get here */ +- abort(); +- +- case SIGHUP: +- /* HUP signal (restart children) */ +- fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid()); +- killChild(); +- killedChild = YES; +- signal(_signal, wsignalHandler); +- return; +- +- case SIGCHLD: +- break; +- +- default: +- fprintf(stderr, "[%i]: watchdog handling signal %i ..\n", +- getpid(), _signal); +- break; ++ max = [readyChildren count]; ++ if (max > delta) ++ max -= delta; ++ for (count = max - 1; count > -1; count--) { ++ child = [readyChildren objectAtIndex: count]; ++ [readyChildren removeObjectAtIndex: count]; ++ [child terminate]; ++ [child setStatus: WOChildStatusExcessive]; ++ delta--; ++ } ++ [self logWithFormat: @"%d processes left to terminate", delta]; + } +- fflush(stderr); +- +- switch (_signal) { +- case SIGTERM: +- case SIGINT: +- case SIGKILL: +- case SIGILL: +- killChild(); +- exit(0); +- break; +- +- case SIGHUP: +- killChild(); +- break; +- +- case SIGCHLD: { +- int returnStatus; +- pid_t result; +- +- // NSLog(@"SIGNAL: SIGCHLD"); +- // fetch return state +- +- do { +- result = waitpid(-1, &returnStatus, WNOHANG); +- if (result > 0) { +- fprintf(stderr, "[%i]: process %i exited with code %i", +- getpid(), (int)result, WEXITSTATUS(returnStatus)); ++} + +- if (WIFSIGNALED(returnStatus)) { +- fprintf(stderr, " (terminated due to signal %i%s)", +- WTERMSIG(returnStatus), +- WCOREDUMP(returnStatus) ? ", coredump" : ""); +- } +- if (WIFSTOPPED(returnStatus)) { +- fprintf(stderr, " (stopped due to signal %i)", +- WSTOPSIG(returnStatus)); +- } +- +- fprintf(stderr, "\n"); +- fflush(stderr); ++- (void) _noop ++{ ++} ++ ++- (BOOL) _ensureChildren ++{ ++ int count, max; ++ WOWatchDogChild *child; ++ BOOL isChild, delayed; ++ NSCalendarDate *now, *nextSpawn; ++ ++ isChild = NO; ++ ++ if (!willTerminate) { ++ [self _ensureNumberOfChildren]; ++ max = [downChildren count]; ++ for (count = max - 1; !isChild && count > -1; count--) { ++ delayed = NO; ++ child = [downChildren objectAtIndex: count]; ++ ++ if ([child status] == WOChildStatusExcessive) ++ [children removeObject: child]; ++ else { ++ now = [NSCalendarDate date]; ++ nextSpawn = [child nextSpawn]; ++ if ([nextSpawn earlierDate: now] == nextSpawn) ++ isChild = [self _spawnChild: child]; ++ else { ++ delayed = YES; ++ [child logNotRespawn]; + } + } +- while (result > 0); +- +- break; ++ if (!delayed) ++ [downChildren removeObjectAtIndex: count]; + } +- +- default: +- fprintf(stderr, "watchdog[%i]: caught signal %i\n", getpid(), _signal); +- break; + } +- signal(_signal, wsignalHandler); ++ ++ return isChild; + } + +-static void signalHandler(int _signal) { +- fprintf(stderr, "[%i]: handling signal %i ..\n", +- getpid(), _signal); +- fflush(stderr); +- +- switch (_signal) { +- case SIGPIPE: +- fprintf(stderr, "[%i]: caught signal SIGPIPE\n", getpid()); +- break; +- +- default: +- fprintf(stderr, "[%i]: caught signal %i\n", getpid(), _signal); +- break; ++/* SOPE on GNUstep does not need to parse the argument line, since the ++ arguments will be put in the NSArgumentDomain. I don't know about ++ libFoundation but OSX is supposed to act the same way. */ ++- (NGInternetSocketAddress *) _listeningAddress ++{ ++ NGInternetSocketAddress *listeningAddress; ++ NSUserDefaults *ud; ++ id port, allow; ++ ++ listeningAddress = nil; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ port = [ud objectForKey:@"p"]; ++ if (!port) { ++ port = [ud objectForKey:@"WOPort"]; ++ if (!port) ++ port = @"auto"; + } +- signal(_signal, signalHandler); ++ allow = [ud objectForKey:@"WOHttpAllowHost"]; ++ if (allow) ++ [self warnWithFormat: @"'WOHttpAllowHost' is ignored in watchdog mode, use a real firewall instead"]; ++ if ([port isKindOfClass: [NSString class]]) { ++ if ([port isEqualToString: @"auto"]) { ++ listeningAddress ++ = [[NGInternetSocketAddress alloc] initWithPort:0 onHost:@"127.0.0.1"]; ++ [listeningAddress autorelease]; ++ } else if ([port rangeOfString: @":"].location == NSNotFound) { ++ if (allow) ++ listeningAddress = ++ [NGInternetSocketAddress wildcardAddressWithPort:[port intValue]]; ++ else ++ port = [NSString stringWithFormat: @"127.0.0.1:%d", [port intValue]]; ++ } ++ } ++ else { ++ if (allow) ++ listeningAddress = ++ [NGInternetSocketAddress wildcardAddressWithPort:[port intValue]]; ++ else { ++ port = [NSString stringWithFormat: @"127.0.0.1:%@", port]; ++ } ++ } ++ ++ if (!listeningAddress) ++ listeningAddress = (NGInternetSocketAddress *) NGSocketAddressFromString(port); ++ ++ return listeningAddress; + } + ++- (BOOL) _prepareListeningSocket ++{ ++ NGInternetSocketAddress *addr; ++ NSString *address; ++ BOOL rc; ++ int backlog; ++ ++ addr = [self _listeningAddress]; ++ NS_DURING { ++ [listeningSocket release]; ++ listeningSocket = [[NGPassiveSocket alloc] initWithDomain: [addr domain]]; ++ [listeningSocket bindToAddress: addr]; ++ backlog = [[NSUserDefaults standardUserDefaults] ++ integerForKey: @"WOListenQueueSize"]; ++ if (!backlog) ++ backlog = 5; ++ [listeningSocket listenWithBacklog: backlog]; ++ address = [addr address]; ++ if (!address) ++ address = @"*"; ++ [self logWithFormat: @"listening on %@:%d", address, [addr port]]; ++ [[NSRunLoop currentRunLoop] addEvent: (void *) [listeningSocket fileDescriptor] ++ type: ET_RDESC ++ watcher: self ++ forMode: NSDefaultRunLoopMode]; ++ rc = YES; ++ } ++ NS_HANDLER { ++ // [self logWithFormat:@"failure listening on address 127.0.0.1:%d", port]; ++ rc = NO; ++ } ++ NS_ENDHANDLER; ++ ++ return rc; ++} ++ ++- (WOWatchDogChild *) _childWithPID: (pid_t) childPid ++{ ++ WOWatchDogChild *currentChild, *child; ++ int count; ++ ++ child = nil; ++ for (count = 0; !child && count < numberOfChildren; count++) { ++ currentChild = [children objectAtIndex: count]; ++ if ([currentChild pid] == childPid) ++ child = currentChild; ++ } ++ ++ return child; ++} ++ ++- (void) _handleSIGPIPE:(NSNumber *)_signal { ++ [self logWithFormat: @"received SIGPIPE (unhandled)"]; ++} ++ ++- (void) _handleSIGCHLD:(NSNumber *)_signal { ++ WOWatchDogChild *child; ++ pid_t childPid; ++ int status; ++ ++ childPid = wait (&status); ++ if (childPid > -1) { ++ pendingSIGCHLD++; ++ child = [self _childWithPID: childPid]; ++ [child setSIGCHLDStatus: status]; ++ } ++} ++ ++- (void) _handleTermination:(NSNumber *)_signal { ++ if (!terminationSignal) { ++ ASSIGN (terminationSignal, _signal); ++ if (pidFile) ++ unlink (pidFile); ++ } ++} ++ ++- (void) _handleSIGHUP:(NSNumber *)_signal { ++ pendingSIGHUP++; ++} ++ ++- (void) _setupSignals ++{ ++#if !defined(__MINGW32__) && !defined(NeXT_Foundation_LIBRARY) ++ UnixSignalHandler *us; ++ ++ us = [UnixSignalHandler sharedHandler]; ++ [us addObserver:self selector:@selector(_handleSIGPIPE:) ++ forSignal:SIGPIPE immediatelyNotifyOnSignal:YES]; ++ [us addObserver:self selector:@selector(_handleSIGCHLD:) ++ forSignal:SIGCHLD immediatelyNotifyOnSignal:YES]; ++ [us addObserver:self selector:@selector(_handleTermination:) ++ forSignal:SIGINT immediatelyNotifyOnSignal:YES]; ++ [us addObserver:self selector:@selector(_handleTermination:) ++ forSignal:SIGTERM immediatelyNotifyOnSignal:YES]; ++ // [us addObserver:self selector:@selector(_handleSIGKILL:) ++ // forSignal:SIGKILL immediatelyNotifyOnSignal:YES]; ++ [us addObserver:self selector:@selector(_handleSIGHUP:) ++ forSignal:SIGHUP immediatelyNotifyOnSignal:YES]; ++#endif ++} ++ ++- (void) declareChildReady: (WOWatchDogChild *) readyChild ++{ ++ [readyChildren addObject: readyChild]; ++} ++ ++- (void) declareChildDown: (WOWatchDogChild *) downChild ++{ ++ if (![downChildren containsObject: downChild]) ++ [downChildren addObject: downChild]; ++} ++ ++- (void) _ensureWorkersCount ++{ ++ int newNumberOfChildren; ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ [ud synchronize]; ++ newNumberOfChildren = [ud integerForKey: @"WOHttpAdaptorForkCount"]; ++ if (newNumberOfChildren) ++ [self logWithFormat: @"user default 'WOHttpAdaptorForkCount' has been" ++ " replaced with 'WOWorkersCount'"]; ++ else ++ newNumberOfChildren = [ud integerForKey: @"WOWorkersCount"]; ++ if (newNumberOfChildren < 1) ++ newNumberOfChildren = 1; ++ numberOfChildren = newNumberOfChildren; ++} ++ ++- (void) _handlePostTerminationSignal ++{ ++ WOWatchDogChild *child; ++ int count; ++ ++ [self logWithFormat: @"Terminating with signal %@", terminationSignal]; ++ [self _releaseListeningSocket]; ++ for (count = 0; count < numberOfChildren; count++) { ++ child = [children objectAtIndex: count]; ++ if ([child status] != WOChildStatusDown ++ && [child status] != WOChildStatusTerminating) ++ [child terminate]; ++ } ++ [terminationSignal release]; ++ terminationSignal = nil; ++ if ([downChildren count] == numberOfChildren) { ++ [self logWithFormat: @"all children exited. We now terminate."]; ++ terminate = YES; ++ } ++ else ++ willTerminate = YES; ++} ++ ++- (void) _handlePostSIGCHLDStatus ++{ ++ int status, count; ++ WOWatchDogChild *child; ++ ++ for (count = 0; pendingSIGCHLD && count < numberOfChildren; count++) { ++ child = [children objectAtIndex: count]; ++ status = [child SIGCHLDStatus]; ++ if (status != -1) { ++ [child handleSIGCHLDStatus]; ++ pendingSIGCHLD--; ++ [self declareChildDown: child]; ++ if (willTerminate && [downChildren count] == numberOfChildren) { ++ [self logWithFormat: @"all children exited. We now terminate."]; ++ terminate = YES; ++ } ++ } ++ } ++} ++ ++- (void) _setupProcessName ++{ ++ NSProcessInfo *processInfo; ++ NSString *name; ++ ++ /* this does not seem to work */ ++ processInfo = [NSProcessInfo processInfo]; ++ name = [processInfo processName]; ++ if (!name) ++ name = @""; ++ [processInfo setProcessName: [NSString stringWithFormat: @"%@: %@ watchdog", ++ name, appName]]; ++} ++ ++- (int) run: (NSString *) newAppName ++ argc: (int) newArgC argv: (const char **) newArgV ++{ ++ NSAutoreleasePool *pool; ++ NSRunLoop *runLoop; ++ NSDate *limitDate; ++ BOOL listening; ++ int retries; ++ ++ willTerminate = NO; ++ ++ ASSIGN (appName, newAppName); ++ [self _setupProcessName]; ++ ++ argc = newArgC; ++ argv = newArgV; ++ ++ listening = NO; ++ retries = 0; ++ while (!listening && retries < 5) { ++ listening = [self _prepareListeningSocket]; ++ retries++; ++ if (!listening) { ++ [self warnWithFormat: @"listening socket: attempt %d failed", retries]; ++ [NSThread sleepForTimeInterval: 1.0]; ++ } ++ } ++ if (listening) { ++ [self logWithFormat: @"watchdog process pid: %d", getpid ()]; ++ [self _setupSignals]; ++ [self _ensureWorkersCount]; ++ ++ // NSLog (@"ready to process requests"); ++ runLoop = [NSRunLoop currentRunLoop]; ++ ++ /* This timer ensures the looping of the runloop at reasonable intervals ++ for correct processing of signal handlers. */ ++ [NSTimer scheduledTimerWithTimeInterval: 0.5 ++ target: self ++ selector: @selector (_noop) ++ userInfo: nil ++ repeats: YES]; ++ terminate = NO; ++ while (!terminate) { ++ pool = [NSAutoreleasePool new]; ++ ++ while (pendingSIGHUP) { ++ [self logWithFormat: @"received SIGHUP"]; ++ [self _ensureWorkersCount]; ++ pendingSIGHUP--; ++ } ++ ++ // [self logWithFormat: @"watchdog loop"]; ++ NS_DURING { ++ terminate = [self _ensureChildren]; ++ if (!terminate) { ++ limitDate = [runLoop limitDateForMode:NSDefaultRunLoopMode]; ++ [runLoop runMode: NSDefaultRunLoopMode beforeDate: limitDate]; ++ } ++ } ++ NS_HANDLER { ++ terminate = YES; ++ [self errorWithFormat: ++ @"an exception occured in runloop %@", localException]; ++ } ++ NS_ENDHANDLER; ++ ++ if (!terminate) { ++ if (terminationSignal) ++ [self _handlePostTerminationSignal]; ++ while (pendingSIGCHLD) ++ [self _handlePostSIGCHLDStatus]; ++ } ++ [pool release]; ++ } ++ ++ [[UnixSignalHandler sharedHandler] removeObserver: self]; ++ } ++ else ++ [self errorWithFormat: @"unable to listen on specified port," ++ @" check that no other process is already using it"]; ++ ++ return 0; ++} ++ ++@end ++ ++static BOOL _writePid(NSString *nsPidFile) { ++ NSString *pid; ++ BOOL rc; ++ ++ pid = [NSString stringWithFormat: @"%d", getpid()]; ++ rc = [pid writeToFile: nsPidFile atomically: NO]; ++ ++ return rc; ++} ++ + int WOWatchDogApplicationMain + (NSString *appName, int argc, const char *argv[]) + { + NSAutoreleasePool *pool; + NSUserDefaults *ud; ++ NSString *logFile, *nsPidFile; ++ int rc, stdErrNo; ++ pid_t childPid; ++ NSProcessInfo *processInfo; + + pool = [[NSAutoreleasePool alloc] init]; ++ + #if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS) + { + extern char **environ; +@@ -241,179 +972,68 @@ + environment:(void*)environ]; + } + #endif +- ++ ++ /* This invocation forces the class initialization of WOCoreApplication, ++ which causes the NSUserDefaults to be initialized as well with ++ Defaults.plist. */ ++ [NSClassFromString (appName) class]; ++ + ud = [NSUserDefaults standardUserDefaults]; +- +- /* default is to use the watch dog! */ +- /* Note: the Defaults.plist is not yet loaded at this stage! */ +- if ([ud objectForKey:@"WOUseWatchDog"] != nil) { +- if (![ud boolForKey:@"WOUseWatchDog"]) +- return WOApplicationMain(appName, argc, argv); ++ processInfo = [NSProcessInfo processInfo]; ++ ++ logFile = [ud objectForKey: @"WOLogFile"]; ++ if (!logFile) ++ logFile = [NSString stringWithFormat: @"/var/log/%@/%@.log", ++ [processInfo processName], ++ [processInfo processName]]; ++ if (![logFile isEqualToString: @"-"]) { ++ stdErrNo = dup(fileno(stderr)); ++ stdout = freopen([logFile cString], "a", stdout); ++ stderr = freopen([logFile cString], "a", stderr); + } +- +- /* watch dog */ +- { +- int failCount = 0; +- int forkCount = 0; +- BOOL repeat = YES; +- BOOL isVerbose = NO; +- +- isVerbose = [[ud objectForKey:@"watchdog_verbose"] boolValue]; +- pidFile = [[[ud objectForKey:@"watchdog_pidfile"] stringValue] copy]; +- +- /* write current pid to pidfile */ +- _writePid(pidFile); +- +- /* register exit handler */ +- atexit(exitWatchdog); +- +- /* register signal handlers of watch dog */ +- signal(SIGPIPE, wsignalHandler); +- signal(SIGCHLD, wsignalHandler); +- signal(SIGINT, wsignalHandler); +- signal(SIGTERM, wsignalHandler); +- signal(SIGKILL, wsignalHandler); +- signal(SIGHUP, wsignalHandler); +- +- /* loop */ +- +- while (repeat) { +- time_t clientStartTime; +- +- clientStartTime = time(NULL); +- killedChild = NO; +- +- if ((child = fork()) == -1) { +- fprintf(stderr, "[%i]: fork failed: %s\n", getpid(), strerror(errno)); +- failCount++; +- +- if (failCount > 5) { +- fprintf(stderr, " fork failed %i times, sleeping 60 seconds ..\n", +- failCount); +- sleep(60); +- } +- else { +- sleep(1); +- } ++ if (stdout && stderr) { ++ if ([ud boolForKey: @"WONoDetach"]) ++ childPid = 0; ++ else ++ childPid = fork(); ++ ++ if (childPid) { ++ rc = 0; ++ } ++ else { ++ nsPidFile = [ud objectForKey: @"WOPidFile"]; ++ if (!nsPidFile) ++ nsPidFile = [NSString stringWithFormat: @"/var/run/%@/%@.pid", ++ [processInfo processName], ++ [processInfo processName]]; ++ pidFile = [nsPidFile UTF8String]; ++ if (_writePid(nsPidFile)) { ++ respawnDelay = [ud integerForKey: @"WORespawnDelay"]; ++ if (!respawnDelay) ++ respawnDelay = 5; ++ /* default is to use the watch dog! */ ++ if ([ud objectForKey:@"WOUseWatchDog"] != nil ++ && ![ud boolForKey:@"WOUseWatchDog"]) ++ rc = WOApplicationMain(appName, argc, argv); ++ else ++ rc = [[WOWatchDog sharedWatchDog] run: appName argc: argc argv: argv]; + } + else { +- if (child == 0) { +- /* child process */ +- signal(SIGPIPE, SIG_DFL); +- signal(SIGCHLD, SIG_DFL); +- signal(SIGINT, SIG_DFL); +- signal(SIGTERM, SIG_DFL); +- signal(SIGKILL, SIG_DFL); +- +- if (isVerbose) +- fprintf(stderr, "starting child %i ..\n", getpid()); +- +- pidFile = [pidFile stringByAppendingPathExtension:@"child"]; +- _writePid(pidFile); +- +- atexit(_delPid); +- +- exit(WOApplicationMain(appName, argc, argv)); +- +- /* shouldn't even get here ! */ +- fprintf(stderr, "internal server error !\n"); +- abort(); +- } +- else { +- /* parent (watch dog) */ +- int status = 0; +- pid_t result = 0; +- time_t clientStopTime; +- unsigned uptime; +- +- forkCount++; +- +- if (isVerbose) { +- fprintf(stderr, "forked child process %i (#%i) ..\n", +- child, forkCount); +- } +- +- failCount = 0; +- status = 0; +- +- if ((result = waitpid(child, &status, 0)) == -1) { +- if (killedChild) { +- killedChild = NO; +- continue; +- } +- +- fprintf(stderr, +- "### waiting for child %i (#%i) failed: %s\n", +- child, forkCount, strerror(errno)); +- continue; +- } +- +- clientStopTime = time(NULL); +- uptime = clientStopTime - clientStartTime; +- +- if (WIFSIGNALED(status)) { +- fprintf(stderr, +- "### child %i (#%i) was terminated by signal %i " +- "(uptime=%ds).\n", +- child, forkCount, WTERMSIG(status), uptime); +- +- lastFailExit = time(NULL); +- failExitCount++; +- } +- else if (WIFEXITED(status)) { +- unsigned exitCode; +- +- if ((exitCode = WEXITSTATUS(status)) != 0) { +- time_t now; +- +- now = time(NULL); +- +- if (uptime < 3) { +- if (failExitCount > 0) { +- unsigned secsSinceLastFail; +- +- secsSinceLastFail = (now - lastFailExit); +- +- if (secsSinceLastFail > 120) { +- /* reset fail count */ +- failExitCount = 0; +- } +- else if (failExitCount > 20) { +- printf("### child %i (#%i) already failed %i times " +- "in the last %i seconds, stopping watchdog !\n", +- child, forkCount, failExitCount, secsSinceLastFail); +- repeat = NO; +- } +- } +- } +- failExitCount++; +- lastFailExit = now; +- +- fprintf(stderr, +- "### child %i (#%i) exited with status %i " +- "(#fails=%i, uptime=%ds).\n", +- child, forkCount, exitCode, failExitCount, uptime); +- } +- else { +- fprintf(stderr, +- "### child %i (#%i) exited successfully (uptime=%ds).\n", +- child, forkCount, uptime); +- } +- +- if (exitCode == 123) // ??? +- repeat = NO; +- } +- else { +- fprintf(stderr, +- "### abnormal termination of child %i (#%i) status=%i" +- "(was not signaled nor exited).", +- child, forkCount, status); +- } +- } ++ [ud errorWithFormat: @"unable to open pid file: %@", pidFile]; ++ rc = -1; + } + } +- return 0; + } ++ else { ++ stdout = fdopen(stdErrNo, "a"); ++ stderr = fdopen(stdErrNo, "a"); ++ fprintf(stderr, "failed to redirect output channels to log file '%s'\n", ++ [logFile cString]); ++ } ++ ++ [pool release]; ++ ++ return rc; + } + #endif + +@@ -421,8 +1041,8 @@ + + @interface NSUserDefaults(ServerDefaults) + + (id)hackInServerDefaults:(NSUserDefaults *)_ud +- withAppDomainPath:(NSString *)_appDomainPath +- globalDomainPath:(NSString *)_globalDomainPath; ++ withAppDomainPath:(NSString *)_appDomainPath ++ globalDomainPath:(NSString *)_globalDomainPath; + @end + + int WOWatchDogApplicationMainWithServerDefaults +@@ -437,7 +1057,7 @@ + { + extern char **environ; + [NSProcessInfo initializeWithArguments:(void*)argv count:argc +- environment:(void*)environ]; ++ environment:(void*)environ]; + } + #endif + +@@ -446,8 +1066,8 @@ + + ud = [NSUserDefaults standardUserDefaults]; + sd = [defClass hackInServerDefaults:ud +- withAppDomainPath:appDomainPath +- globalDomainPath:globalDomainPath]; ++ withAppDomainPath:appDomainPath ++ globalDomainPath:globalDomainPath]; + + #if 0 + if (((sd == nil) || (sd == ud)) && (appDomainPath != nil)) { +Index: sope-appserver/NGObjWeb/GNUmakefile.postamble +=================================================================== +--- sope-appserver/NGObjWeb/GNUmakefile.postamble (revision 1664) ++++ sope-appserver/NGObjWeb/GNUmakefile.postamble (working copy) +@@ -23,14 +23,20 @@ + + # install makefiles + +-after-install :: +- $(MKDIRS) $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ +- $(INSTALL_DATA) ngobjweb.make $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make ++after-install :: $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make + + ifneq ($(GNUSTEP_MAKE_VERSION),1.3.0) +-after-install :: ++after-install :: $(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make ++endif ++ ++$(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make: ngobjweb.make ++ $(MKDIRS) $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ ++ $(INSTALL_DATA) ngobjweb.make $(DESTDIR)/$(GNUSTEP_MAKEFILES)/Additional/ngobjweb.make ++ ++$(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make: woapp-gs.make + $(INSTALL_DATA) woapp-gs.make \ +- $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/woapp.make ++ $(DESTDIR)/$(GNUSTEP_MAKEFILES)/woapp.make ++ ++$(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make: wobundle-gs.make + $(INSTALL_DATA) wobundle-gs.make \ +- $(INSTALL_ROOT_DIR)/$(GNUSTEP_MAKEFILES)/wobundle.make +-endif ++ $(DESTDIR)/$(GNUSTEP_MAKEFILES)/wobundle.make +Index: sope-appserver/NGObjWeb/WOMessage+XML.m +=================================================================== +--- sope-appserver/NGObjWeb/WOMessage+XML.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOMessage+XML.m (working copy) +@@ -84,7 +84,7 @@ + id builder; + + builder = [[[NSClassFromString(@"DOMSaxBuilder") alloc] init] autorelease]; +- dom = [[builder buildFromData:data] retain]; ++ dom = [builder buildFromData:data]; + } + + /* cache DOM structure */ +Index: sope-appserver/NGObjWeb/ChangeLog +=================================================================== +--- sope-appserver/NGObjWeb/ChangeLog (revision 1664) ++++ sope-appserver/NGObjWeb/ChangeLog (working copy) +@@ -1,3 +1,97 @@ ++2009-12-22 Wolfgang Sourdeau ++ ++ * WOWatchDogApplicationMain.m (_listeningAddress): read "WOPort" ++ from the user defaults rather than by invoking [WOApplication ++ port], which returns an NSNumber. ++ ++2009-12-14 Wolfgang Sourdeau ++ ++ * WOWatchDogApplicationMain.m (-run:argc:argv:): added a ++ repeatable timer, triggered every 0.5 seconds, that ensures the ++ proper looping of the runloop when a signal was received. ++ ++2009-12-09 Wolfgang Sourdeau ++ ++ * WOWatchDogApplicationMain.m (_handleSIGCHLD:) ++ (_handleTermination:, _handleSIGHUP:): the actual handling is now ++ done elsewhere, in order to avoid messing with memory allocation ++ and risking a dead lock. ++ (-_handlePostTerminationSignal): we set "terminate" to YES if all ++ children are already down, in order to avoid another deadlock ++ where the process termination would stall waiting for SIGCHLD. ++ (-receivedEvent:type:extra:forMode:): check that the control ++ socket is still "alive" before reading from it. If not, we ++ unregister the filedescriptor passed as "data" from the runloop ++ listener. ++ ++2009-12-07 Wolfgang Sourdeau ++ ++ * WOCoreApplication.m (+initialize): we invoke ++ "registerUserDefaults" from here now. This enables Defaults.plist ++ to be registered as soon as the watchdog is active. ++ ++ * WOWatchDogApplicationMain.m (-terminate): we use a SIGTERM to ++ terminate the children instead of passing a message. We also setup ++ a timer that will send a SIGKILL after 5 minutes. ++ (-_releaseListeningSocket): we close the socket here so that other ++ processes can start listening. ++ (WOWatchDogApplicationMain): we accept "-" as argument to ++ "WOLogFile" so that we avoid redirecting the output and the error ++ channels. ++ ++2009-11-11 Wolfgang Sourdeau ++ ++ * WOCoreApplication.m (-setControlSocket, -controlSocket) ++ (-setListeningSocket, -listeningSocke): new helper accessors for ++ the new watchdog mechanism. ++ ++ * WOHttpAdaptor/WOHttpAdaptor.m: slightly refactored to use the ++ control socket provided by the watchdog. ++ ++ * WOWatchDogApplicationMain.m: rewritten the watchdog mechanism: ++ - added WOWatchDog and WOWatchDogChild classes ++ - make use of UnixSignalHandler ++ - added support for preforked preocesses (WOWorkersCount) ++ - detach watchdog processes from terminal by default (WONoDetach) ++ - redirect stderr and stdout to file ++ (WOLogFile = /var/log/[name]/[name].log) ++ - write pid file ++ (WOPidFile = /var/run/[name]/[name].pid) ++ - use "127.0.0.1:port" as default bind address, unless ++ WOHTTPAllowHost is specified ++ - added support for delaying process respawning ++ (WORespawnDelay = 5 seconds) ++ ++2009-10-26 Wolfgang Sourdeau ++ ++ * WOMessage+XML.m (-contentAsDOMDocument): do not retain "dom" as ++ it will be assigned to self->domCache, to avoid a leak. ++ ++2009-10-21 Wolfgang Sourdeau ++ ++ * WebDAV/SoObjectResultEntry.m (-valueForKey:): we now take ++ WOUseRelativeURLs into account when the "href" key is requested, ++ to work around a bug in iCal 4. ++ ++2009-07-02 Wolfgang Sourdeau ++ ++ * WOMessage.m (-setHeaders:, -setHeader:forKey:, headerForKey:, ++ -appendHeader:forKey:, -appendHeaders:forKey:, setHeaders:forKey:, ++ -headersForKey:): convert the specified header key to lowercase, ++ to ensure they are managed case-insensitively. ++ * WOHttpAdaptor/WOHttpTransaction.m ++ (-deliverResponse:toRequest:onStream:): if the content-type is ++ specified and already has "text/plain" as prefix, we don't ++ override it. ++ ++2009-07-01 Wolfgang Sourdeau ++ ++ * WOHttpAdaptor/WOHttpTransaction.m ++ (-deliverResponse:toRequest:onStream:): we test the content-length ++ and impose a content-type of text/plain when 0. This work-arounds ++ a bug in Mozilla clients where empty responses with a content-type ++ set to X/xml will trigger an exception. ++ + 2009-06-10 Helge Hess + + * DAVPropMap.plist: mapped {DAV:}current-user-principal (v4.9.37) +Index: sope-appserver/NGObjWeb/DAVPropMap.plist +=================================================================== +--- sope-appserver/NGObjWeb/DAVPropMap.plist (revision 1664) ++++ sope-appserver/NGObjWeb/DAVPropMap.plist (working copy) +@@ -157,6 +157,7 @@ + "{urn:ietf:params:xml:ns:caldav}supported-calendar-data" = + davSupportedCalendarDataTypes; + "{urn:ietf:params:xml:ns:caldav}calendar-description" = davDescription; ++ "{urn:ietf:params:xml:ns:caldav}calendar-timezone" = davCalendarTimeZone; + + /* CardDAV */ + "{urn:ietf:params:xml:ns:carddav}addressbook-home-set" = davAddressbookHomeSet; +Index: sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m +=================================================================== +--- sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (revision 1664) ++++ sope-appserver/NGObjWeb/WebDAV/SoObjectResultEntry.m (working copy) +@@ -25,7 +25,14 @@ + @implementation SoObjectResultEntry + + static BOOL debugOn = NO; ++static BOOL useRelativeURLs = NO; + +++ (void) initialize ++{ ++ useRelativeURLs = [[NSUserDefaults standardUserDefaults] ++ boolForKey: @"WOUseRelativeURLs"]; ++} ++ + - (id)initWithURI:(NSString *)_href object:(id)_o values:(NSDictionary *)_d { + if ((self = [super init])) { + if (debugOn) { +@@ -85,10 +92,36 @@ + return YES; + } + ++- (NSString *)_relativeHREF { ++ NSString *newHREF; ++ NSRange hostRange; ++ ++ if ([self->href hasPrefix: @"/"]) ++ return self->href; ++ else { ++ hostRange = [self->href rangeOfString: @"://"]; ++ if (hostRange.length > 0) { ++ newHREF = [self->href substringFromIndex: NSMaxRange (hostRange)]; ++ hostRange = [newHREF rangeOfString: @"/"]; ++ if (hostRange.length > 0) { ++ newHREF = [newHREF substringFromIndex: hostRange.location]; ++ } ++ } else { ++ newHREF = self->href; ++ } ++ ++ return newHREF; ++ } ++} ++ + - (id)valueForKey:(NSString *)_key { +- if ([_key isEqualToString:@"{DAV:}href"]) +- return self->href; +- ++ if ([_key isEqualToString:@"{DAV:}href"]) { ++ if (useRelativeURLs) ++ return [self _relativeHREF]; ++ else ++ return self->href; ++ } ++ + if ([_key isEqualToString:@"{DAV:}status"]) + return nil; + +Index: sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m +=================================================================== +--- sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (revision 1664) ++++ sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m (working copy) +@@ -49,6 +49,8 @@ + #define XMLNS_INTTASK \ + @"{http://schemas.microsoft.com/mapi/id/{00062003-0000-0000-C000-000000000046}/}" + ++static Class NSURLKlass = Nil; ++ + @interface SoWebDAVRenderer(Privates) + - (BOOL)renderStatusResult:(id)_object withDefaultStatus:(int)_defStatus + inContext:(WOContext *)_ctx; +@@ -79,6 +81,8 @@ + + if ((debugOn = [ud boolForKey:@"SoRendererDebugEnabled"])) + NSLog(@"enabled debugging in SoWebDAVRenderer (SoRendererDebugEnabled)"); ++ ++ NSURLKlass = [NSURL class]; + } + + + (id)sharedRenderer { +@@ -616,16 +620,19 @@ + [r appendContentString:s]; + } + else { ++ s = [self stringForValue:value ofProperty:_key prefixes:nsToPrefix]; + [r appendContentCharacter:'<']; + [r appendContentString:extName]; +- [r appendContentCharacter:'>']; +- +- s = [self stringForValue:value ofProperty:_key prefixes:nsToPrefix]; +- [r appendContentString:s]; +- +- [r appendContentString:@""]; ++ if ([s length] > 0) { ++ [r appendContentCharacter:'>']; ++ [r appendContentString:s]; ++ [r appendContentString:@""]; ++ } ++ else { ++ [r appendContentString:@"/>"]; ++ } + if (formatOutput) [r appendContentCharacter:'\n']; + } + } +@@ -694,8 +701,13 @@ + } + + /* tidy href */ +- href = [self tidyHref:href baseURL:baseURL]; +- ++ if (useRelativeURLs) { ++ if ([href isKindOfClass: NSURLKlass]) ++ href = [href path]; ++ } ++ else ++ href = [self tidyHref:href baseURL:baseURL]; ++ + /* tidy status */ + stat = [self tidyStatus:stat]; + } +Index: sope-appserver/NGObjWeb/WODirectAction.m +=================================================================== +--- sope-appserver/NGObjWeb/WODirectAction.m (revision 1664) ++++ sope-appserver/NGObjWeb/WODirectAction.m (working copy) +@@ -46,7 +46,7 @@ + } + - (id)initWithContext:(WOContext *)_ctx { + if ((self = [self initWithRequest:[_ctx request]])) { +- self->context = [_ctx retain]; ++ self->context = _ctx; + } + return self; + } +@@ -54,16 +54,16 @@ + return [self initWithRequest:nil]; + } + +-- (void)dealloc { +- [self->context release]; +- [super dealloc]; +-} ++// - (void)dealloc { ++// [self->context release]; ++// [super dealloc]; ++// } + + /* accessors */ + + - (WOContext *)context { + if (self->context == nil) +- self->context = [[[WOApplication application] context] retain]; ++ self->context = [[WOApplication application] context]; + return self->context; + } + +Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m +=================================================================== +--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (revision 1664) ++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.m (working copy) +@@ -216,6 +216,12 @@ + assocCount++; + } + } ++ if (count > 0) { ++ if ((self->isAbsolute = OWGetProperty(_config, @"absolute"))) { ++ count--; ++ assocCount++; ++ } ++ } + + self->rest = _config; + +Index: sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m +=================================================================== +--- sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (revision 1664) ++++ sope-appserver/NGObjWeb/DynamicElements/_WOComplexHyperlink.m (working copy) +@@ -41,6 +41,7 @@ + WOAssociation *string; + WOAssociation *target; + WOAssociation *disabled; ++ WOAssociation *isAbsolute; + WOElement *template; + + /* new in WO4: */ +@@ -360,6 +361,7 @@ + { + if ((self = [super initWithName:_name hyperlinkInfo:_info template:_t])) { + self->href = _info->href; ++ self->isAbsolute = _info->isAbsolute; + } + return self; + } +@@ -375,8 +377,11 @@ + // TODO: we need a binding to disable rewriting! + NSRange r; + ++ if ([[self->isAbsolute valueInContext:_ctx] boolValue] == YES) ++ return NO; ++ + r.length = [_s length]; +- ++ + /* do not rewrite pure fragment URLs */ + if (r.length > 0 && [_s characterAtIndex:0] == '#') + return NO; +Index: sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h +=================================================================== +--- sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (revision 1664) ++++ sope-appserver/NGObjWeb/DynamicElements/WOHyperlinkInfo.h (working copy) +@@ -41,7 +41,8 @@ + WOAssociation *pageName; + WOAssociation *actionClass; + WOAssociation *directActionName; +- ++ WOAssociation *isAbsolute; ++ + BOOL sidInUrl; + + /* 'ivar' associations */ +Index: sope-appserver/NGObjWeb/WOMessage.m +=================================================================== +--- sope-appserver/NGObjWeb/WOMessage.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOMessage.m (working copy) +@@ -182,7 +182,7 @@ + NSString *key; + + keys = [_headers keyEnumerator]; +- while ((key = [keys nextObject])) { ++ while ((key = [[keys nextObject] lowercaseString])) { + id value; + + value = [_headers objectForKey:key]; +@@ -198,34 +198,39 @@ + } + + - (void)setHeader:(NSString *)_header forKey:(NSString *)_key { +- [self->header setObject:[_header stringValue] forKey:_key]; ++ [self->header setObject:[_header stringValue] ++ forKey:[_key lowercaseString]]; + } + - (NSString *)headerForKey:(NSString *)_key { +- return [[self->header objectEnumeratorForKey:_key] nextObject]; ++ return [[self->header objectEnumeratorForKey:[_key lowercaseString]] ++ nextObject]; + } + + - (void)appendHeader:(NSString *)_header forKey:(NSString *)_key { +- [self->header addObject:_header forKey:_key]; ++ [self->header addObject:_header forKey:[_key lowercaseString]]; + } + - (void)appendHeaders:(NSArray *)_headers forKey:(NSString *)_key { +- [self->header addObjects:_headers forKey:_key]; ++ [self->header addObjects:_headers forKey:[_key lowercaseString]]; + } + + - (void)setHeaders:(NSArray *)_headers forKey:(NSString *)_key { + NSEnumerator *e; + id value; ++ NSString *lowerKey; + ++ lowerKey = [_key lowercaseString]; + e = [_headers objectEnumerator]; + +- [self->header removeAllObjectsForKey:_key]; ++ [self->header removeAllObjectsForKey:lowerKey]; + + while ((value = [e nextObject])) +- [self->header addObject:value forKey:_key]; ++ [self->header addObject:value forKey:lowerKey]; + } + - (NSArray *)headersForKey:(NSString *)_key { + NSEnumerator *values; + +- if ((values = [self->header objectEnumeratorForKey:_key])) { ++ if ((values ++ = [self->header objectEnumeratorForKey:[_key lowercaseString]])) { + NSMutableArray *array = nil; + id value = nil; + +@@ -243,17 +248,14 @@ + NSEnumerator *values; + + if ((values = [self->header keyEnumerator])) { +- NSMutableArray *array = nil; ++ NSMutableArray *array; + id name = nil; +- array = [[NSMutableArray alloc] init]; +- ++ array = [NSMutableArray array]; ++ + while ((name = [values nextObject])) + [array addObject:name]; + +- name = [array copy]; +- [array release]; +- +- return [name autorelease]; ++ return array; + } + return nil; + } +Index: sope-appserver/NGObjWeb/SoObjects/SoObject.m +=================================================================== +--- sope-appserver/NGObjWeb/SoObjects/SoObject.m (revision 1664) ++++ sope-appserver/NGObjWeb/SoObjects/SoObject.m (working copy) +@@ -39,22 +39,34 @@ + static int debugLookup = -1; + static int debugBaseURL = -1; + static int useRelativeURLs = -1; ++static int redirectInitted = -1; ++static NSURL *redirectURL = nil; ++ + static void _initialize(void) { ++ NSString *url; ++ NSUserDefaults *ud; ++ ++ ud = [NSUserDefaults standardUserDefaults]; ++ + if (debugLookup == -1) { +- debugLookup = [[NSUserDefaults standardUserDefaults] +- boolForKey:@"SoDebugKeyLookup"] ? 1 : 0; ++ debugLookup = [ud boolForKey:@"SoDebugKeyLookup"] ? 1 : 0; + NSLog(@"Note(SoObject): SoDebugKeyLookup is enabled!"); + } + if (debugBaseURL == -1) { +- debugBaseURL = [[NSUserDefaults standardUserDefaults] +- boolForKey:@"SoDebugBaseURL"] ? 1 : 0; ++ debugBaseURL = [ud boolForKey:@"SoDebugBaseURL"] ? 1 : 0; + NSLog(@"Note(SoObject): SoDebugBaseURL is enabled!"); + } + if (useRelativeURLs == -1) { +- useRelativeURLs = [[NSUserDefaults standardUserDefaults] +- boolForKey:@"WOUseRelativeURLs"] ?1:0; ++ useRelativeURLs = [ud boolForKey:@"WOUseRelativeURLs"] ?1:0; + NSLog(@"Note(SoObject): relative base URLs are enabled."); + } ++ if (redirectInitted == -1) { ++ url = [ud stringForKey:@"WOApplicationRedirectURL"]; ++ if ([url length]) { ++ redirectURL = [[NSURL alloc] initWithString: url]; ++ } ++ redirectInitted = 1; ++ } + } + + /* classes */ +@@ -318,56 +330,61 @@ + + rq = [_ctx request]; + ms = [[NSMutableString alloc] initWithCapacity:128]; ++ ++ if (redirectURL) { ++ [ms appendString: [redirectURL absoluteString]]; ++ } ++ else { ++ if (!useRelativeURLs) { ++ port = [[rq headerForKey:@"x-webobjects-server-port"] intValue]; + +- if (!useRelativeURLs) { +- port = [[rq headerForKey:@"x-webobjects-server-port"] intValue]; +- +- /* this is actually a bug in Apache */ +- if (port == 0) { +- static BOOL didWarn = NO; +- if (!didWarn) { +- [self warnWithFormat:@"(%s:%i): got an empty port from Apache!", +- __PRETTY_FUNCTION__, __LINE__]; +- didWarn = YES; ++ /* this is actually a bug in Apache */ ++ if (port == 0) { ++ static BOOL didWarn = NO; ++ if (!didWarn) { ++ [self warnWithFormat:@"(%s:%i): got an empty port from Apache!", ++ __PRETTY_FUNCTION__, __LINE__]; ++ didWarn = YES; ++ } ++ port = 80; + } +- port = 80; +- } + +- if ((tmp = [rq headerForKey:@"host"]) != nil) { +- /* check whether we have a host header with port */ +- if ([tmp rangeOfString:@":"].length == 0) +- tmp = nil; +- } +- if (tmp != nil) { /* we have a host header with port */ +- isHTTPS = +- [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"]; +- [ms appendString:isHTTPS ? @"https://" : @"http://"]; +- [ms appendString:tmp]; +- } +- else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"]) != nil) { +- /* sometimes the URL is just wrong! (suggests port 80) */ +- if ([tmp hasSuffix:@":0"] && [tmp length] > 2) { // TODO: bad bad bad +- [self warnWithFormat:@"%s: got incorrect URL from Apache: '%@'", +- __PRETTY_FUNCTION__, tmp]; +- tmp = [tmp substringToIndex:([tmp length] - 2)]; ++ if ((tmp = [rq headerForKey:@"host"]) != nil) { ++ /* check whether we have a host header with port */ ++ if ([tmp rangeOfString:@":"].length == 0) ++ tmp = nil; + } +- else if ([tmp hasSuffix:@":443"] && [tmp hasPrefix:@"http://"]) { +- /* see OGo bug #1435, Debian Apache hack */ +- [self warnWithFormat:@"%s: got 'http' protocol but 443 port, " +- @"assuming Debian/Apache bug (OGo #1435): '%@'", +- __PRETTY_FUNCTION__, tmp]; +- tmp = [tmp substringWithRange:NSMakeRange(4, [tmp length] - 4 - 4)]; +- tmp = [@"https" stringByAppendingString:tmp]; ++ if (tmp != nil) { /* we have a host header with port */ ++ isHTTPS = ++ [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"]; ++ [ms appendString:isHTTPS ? @"https://" : @"http://"]; ++ [ms appendString:tmp]; + } +- [ms appendString:tmp]; +- } +- else { +- // TODO: isHTTPS always no in this case? +- [ms appendString:isHTTPS ? @"https://" : @"http://"]; ++ else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"]) != nil) { ++ /* sometimes the URL is just wrong! (suggests port 80) */ ++ if ([tmp hasSuffix:@":0"] && [tmp length] > 2) { // TODO: bad bad bad ++ [self warnWithFormat:@"%s: got incorrect URL from Apache: '%@'", ++ __PRETTY_FUNCTION__, tmp]; ++ tmp = [tmp substringToIndex:([tmp length] - 2)]; ++ } ++ else if ([tmp hasSuffix:@":443"] && [tmp hasPrefix:@"http://"]) { ++ /* see OGo bug #1435, Debian Apache hack */ ++ [self warnWithFormat:@"%s: got 'http' protocol but 443 port, " ++ @"assuming Debian/Apache bug (OGo #1435): '%@'", ++ __PRETTY_FUNCTION__, tmp]; ++ tmp = [tmp substringWithRange:NSMakeRange(4, [tmp length] - 4 - 4)]; ++ tmp = [@"https" stringByAppendingString:tmp]; ++ } ++ [ms appendString:tmp]; ++ } ++ else { ++ // TODO: isHTTPS always no in this case? ++ [ms appendString:isHTTPS ? @"https://" : @"http://"]; + +- [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]]; +- if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0) +- [ms appendFormat:@":%i", port]; ++ [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]]; ++ if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0) ++ [ms appendFormat:@":%i", port]; ++ } + } + } + +Index: sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h +=================================================================== +--- sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h (revision 1664) ++++ sope-appserver/NGObjWeb/NGObjWeb/WOAdaptor.h (working copy) +@@ -27,6 +27,13 @@ + @class NSString, NSDictionary; + @class WOCoreApplication; + ++typedef enum { ++ WOChildMessageAccept = 0, ++ WOChildMessageReady, ++ WOChildMessageShutdown, ++ WOChildMessageMax ++} WOChildMessage; ++ + @interface WOAdaptor : NSObject + { + @protected +Index: sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h +=================================================================== +--- sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h (revision 1664) ++++ sope-appserver/NGObjWeb/NGObjWeb/WOCoreApplication.h (working copy) +@@ -31,6 +31,8 @@ + @class WOAdaptor, WORequest, WOResponse, WORequestHandler; + @class NSBundle; + ++@class NGActiveSocket, NGPassiveSocket; ++ + NGObjWeb_EXPORT NSString *WOApplicationWillFinishLaunchingNotification; + NGObjWeb_EXPORT NSString *WOApplicationDidFinishLaunchingNotification; + NGObjWeb_EXPORT NSString *WOApplicationWillTerminateNotification; +@@ -41,6 +43,9 @@ + NSRecursiveLock *lock; + NSLock *requestLock; + ++ NGActiveSocket *controlSocket; ++ NGPassiveSocket *listeningSocket; ++ + struct { + BOOL isTerminating:1; + } cappFlags; +@@ -55,6 +60,14 @@ + - (void)activateApplication; + - (void)deactivateApplication; + ++/* Watchdog helpers */ ++ ++- (void)setControlSocket: (NGActiveSocket *) newSocket; ++- (NGActiveSocket *)controlSocket; ++ ++- (void)setListeningSocket: (NGPassiveSocket *) newSocket; ++- (NGPassiveSocket *)listeningSocket; ++ + /* adaptors */ + + - (NSArray *)adaptors; +Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h +=================================================================== +--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h (revision 1664) ++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.h (working copy) +@@ -46,7 +46,6 @@ + NSMutableArray *delayedResponses; + } + +-+ (BOOL)optionLogStream; + + (BOOL)optionLogPerf; + + @end +Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m +=================================================================== +--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpTransaction.m (working copy) +@@ -48,8 +48,8 @@ + NSString *WOAsyncResponseReadyNotificationName = + @"WOAsyncResponseReadyNotification"; + NSString *WOAsyncResponse = @"WOAsyncResponse"; ++static BOOL WOHttpAdaptor_LogStream = NO; + +- + @interface WOCoreApplication(SimpleParserSelection) + + - (BOOL)shouldUseSimpleHTTPParserForTransaction:(id)_tx; +@@ -85,13 +85,14 @@ + ud = [NSUserDefaults standardUserDefaults]; + useSimpleParser = [ud boolForKey:@"WOHttpTransactionUseSimpleParser"]; + doCore = [[ud objectForKey:@"WOCoreOnHTTPAdaptorException"] boolValue]?1:0; ++ WOHttpAdaptor_LogStream = [ud boolForKey:@"WOHttpAdaptor_LogStream"]; + + adLogPath = [[ud stringForKey:@"WOAdaptorLogPath"] copy]; + if (adLogPath == nil) adLogPath = @""; + } + + - (BOOL)optionLogStream { +- return [WOHttpAdaptor optionLogStream]; ++ return WOHttpAdaptor_LogStream; + } + - (BOOL)optionLogPerf { + return perfLogger ? YES : NO; +@@ -108,6 +109,9 @@ + NSAssert(_app, @"missing application ..."); + self->socket = [_socket retain]; + self->application = [_app retain]; ++ if ([[_app recordingPath] length] > 0) ++ WOHttpAdaptor_LogStream = YES; ++ + return self; + } + +@@ -696,7 +700,7 @@ + *(&out) = nil; + + [self _httpValidateResponse:_response]; +- ++ + out = [(NGCTextStream *)[NGCTextStream alloc] initWithSource:_out]; + + NS_DURING { +@@ -705,6 +709,7 @@ + id body; + BOOL doZip; + BOOL isok = YES; ++ int length; + + doZip = [_response shouldZipResponseToRequest:_request]; + +@@ -738,7 +743,11 @@ + + /* add content length header */ + +- snprintf((char *)buf, sizeof(buf), "%d", [body length]); ++ if ((length = [body length]) == 0 ++ && ![[_response headerForKey: @"content-type"] hasPrefix:@"text/plain"]) { ++ [_response setHeader:@"text/plain" forKey:@"content-type"]; ++ } ++ snprintf((char *)buf, sizeof(buf), "%d", length); + t1 = [[NSString alloc] initWithCString:(char *)buf]; + [_response setHeader:t1 forKey:@"content-length"]; + [t1 release]; t1 = nil; +@@ -766,7 +775,7 @@ + NSString *value; + + if (!hasConnectionHeader) { +- if ([fieldName caseInsensitiveCompare:@"connection"]==NSOrderedSame) ++ if ([fieldName isEqualToString:@"connection"]) + hasConnectionHeader = YES; + } + +Index: sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m +=================================================================== +--- sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOHttpAdaptor/WOHttpAdaptor.m (working copy) +@@ -71,18 +71,13 @@ + + static NGLogger *logger = nil; + static NGLogger *perfLogger = nil; +-static BOOL WOHttpAdaptor_LogStream = NO; + static BOOL WOContactSNS = NO; + static BOOL WOCoreOnHTTPAdaptorException = NO; + static int WOHttpAdaptorSendTimeout = 10; + static int WOHttpAdaptorReceiveTimeout = 10; +-static int WOHttpAdaptorForkCount = 0; + static id allow = nil; + static BOOL debugOn = NO; + +-+ (BOOL)optionLogStream { +- return WOHttpAdaptor_LogStream; +-} + + (BOOL)optionLogPerf { + return perfLogger != nil ? YES : NO; + } +@@ -108,8 +103,6 @@ + logger = [lm loggerForClass:self]; + perfLogger = [lm loggerForDefaultKey:@"WOProfileHttpAdaptor"]; + +- WOHttpAdaptor_LogStream = [ud boolForKey:@"WOHttpAdaptor_LogStream"]; +- + // TODO: this should be queried on demand to allow different defaults + WOContactSNS = [[ud objectForKey:@"WOContactSNS"] boolValue]; + +@@ -134,9 +127,6 @@ + allow = [allow copy]; + } + +- WOHttpAdaptorForkCount = +- [[ud objectForKey:@"WOHttpAdaptorForkCount"] intValue]; +- + if (WOCoreOnHTTPAdaptorException) + [logger warnWithFormat:@"will dump core on HTTP adaptor exception!"]; + } +@@ -219,33 +209,31 @@ + application:_application])) { + id arg = nil; + +- if ([[_application recordingPath] length] > 0) +- WOHttpAdaptor_LogStream = YES; +- + [self _registerForSignals]; ++ if (![_application controlSocket]) { ++ if ([_args count] < 1) ++ self->address = [self addressFromDefaultsOfApplication:_application]; ++ else ++ self->address = [self addressFromArguments:_args]; + +- if ([_args count] < 1) +- self->address = [self addressFromDefaultsOfApplication:_application]; +- else +- self->address = [self addressFromArguments:_args]; ++ self->address = [self->address retain]; + +- self->address = [self->address retain]; ++ if (self->address == nil) { ++ [_application errorWithFormat: ++ @"got no address for HTTP server (using arg '%@')", arg]; ++ [self release]; ++ return nil; ++ } + +- if (self->address == nil) { +- [_application errorWithFormat: +- @"got no address for HTTP server (using arg '%@')", arg]; +- [self release]; +- return nil; +- } +- +- if (!WOContactSNS) { +- [_application logWithFormat:@"%@ listening on address %@", ++ if (!WOContactSNS) { ++ [_application logWithFormat:@"%@ listening on address %@", + NSStringFromClass([self class]), + [(id)self->address stringValue]]; ++ } + } + + self->lock = [[NSRecursiveLock alloc] init]; +- ++ + self->maxThreadCount = [[WOCoreApplication workerThreadCount] intValue]; + + [self setSendTimeout:WOHttpAdaptorSendTimeout]; +@@ -270,145 +258,76 @@ + return self->address; + } + +-/* forking */ +- +-static pid_t *childPIDs = NULL; +-static BOOL isForkMaster = YES; +- +-- (void)forkChildren { +- unsigned i; +- +- if (WOHttpAdaptorForkCount == 0) +- return; +- +- [self logWithFormat:@"Note: forking %d children for socket processing.", +- WOHttpAdaptorForkCount]; +- +-#if !defined(__MINGW32__) +- [[UnixSignalHandler sharedHandler] +- addObserver:self selector:@selector(handleSIGCHLD:) +- forSignal:SIGCHLD immediatelyNotifyOnSignal:NO]; +-#endif +- +- childPIDs = calloc(WOHttpAdaptorForkCount + 1, sizeof(pid_t)); +- for (i = 0; i < WOHttpAdaptorForkCount; i++) { +- childPIDs[i] = fork(); +- +- if (childPIDs[i] == 0) { +- /* child */ +- isForkMaster = NO; +- return; +- } +- else if (childPIDs[i] > 0) +- printf("Note: successfully forked child: %i\n", childPIDs[i]); +- else +- [self errorWithFormat:@"failed to fork child %i.", i]; +- } +-} +-- (void)killChildren { +- int i; +- +- if (!isForkMaster) +- return; +- +- for (i = 0; i < WOHttpAdaptorForkCount; i++) { +- if (childPIDs[i] != 0) +- kill(childPIDs[i], SIGKILL); +- } +-} +- +-- (void)checkStatusOfChildren { +- /* +- Note: currently this does not refork crashed processes. Reforking is harder +- than it may sound because the crash can happen at arbitary execution +- states. +- That is, the "master process" is not virgin anymore, eg it might have +- open database connections. +- +- So the solution might be to refork the whole cluster once a minimum +- backend threshold is reached. +- */ +- unsigned int i; +- +- if (!isForkMaster) +- return; +- +- for (i = 0; i < WOHttpAdaptorForkCount; i++) { +- pid_t result; +- int status; +- +- if (childPIDs[i] == 0) +- continue; +- +- result = waitpid(childPIDs[i], &status, WNOHANG); +- if (result == 0) /* did not exit yet */ +- continue; +- +- if (result == -1) { /* error */ +- [self errorWithFormat:@"failed to get status of child %i: %s", +- childPIDs[i], strerror(errno)]; +- continue; +- } +- +- [self logWithFormat:@"Note: child %i terminated.", childPIDs[i]]; +- childPIDs[i] = 0; +- } +-} +- + /* events */ + + - (void)handleSIGPIPE:(int)_signal { + [self warnWithFormat:@"caught SIGPIPE !"]; + } +-- (void)handleSIGCHLD:(int)_signal { +- [self checkStatusOfChildren]; +-} + + - (void)registerForEvents { + int backlog; ++ NGActiveSocket *controlSocket; ++ WOChildMessage message; ++ ++ controlSocket = [[WOCoreApplication application] controlSocket]; ++ if (controlSocket) { ++ ASSIGN(self->socket, [[WOCoreApplication application] listeningSocket]); ++ [[NSNotificationCenter defaultCenter] ++ addObserver:self ++ selector:@selector(acceptControlMessage:) ++ name:NSFileObjectBecameActiveNotificationName ++ object:nil]; ++ [(WORunLoop *)[WORunLoop currentRunLoop] ++ addFileObject:controlSocket ++ activities:NSPosixReadableActivity ++ forMode:NSDefaultRunLoopMode]; ++ message = WOChildMessageReady; ++ [controlSocket safeWriteBytes: &message ++ count: sizeof (WOChildMessage)]; ++ // [self logWithFormat: @"notified the watchdog that we are ready"]; ++ } ++ else { ++ backlog = [[WOCoreApplication listenQueueSize] intValue]; + +- backlog = [[WOCoreApplication listenQueueSize] intValue]; ++ if (backlog == 0) ++ backlog = 5; + +- if (backlog == 0) +- backlog = 5; ++ [self->socket release]; self->socket = nil; + +- [self->socket release]; self->socket = nil; ++ self->socket = ++ [[NGPassiveSocket alloc] initWithDomain:[self->address domain]]; + +- self->socket = +- [[NGPassiveSocket alloc] initWithDomain:[self->address domain]]; ++ [self->socket bindToAddress:self->address]; + +- [self->socket bindToAddress:self->address]; +- +- if ([[self->address domain] isEqual:[NGInternetSocketDomain domain]]) { +- if ([(NGInternetSocketAddress *)self->address port] == 0) { +- /* let the kernel choose an IP address */ ++ if ([[self->address domain] isEqual:[NGInternetSocketDomain domain]]) { ++ if ([(NGInternetSocketAddress *)self->address port] == 0) { ++ /* let the kernel choose an IP address */ + +- [self debugWithFormat:@"bound to wildcard: %@", self->address]; +- [self debugWithFormat:@"got local: %@", [self->socket localAddress]]; ++ [self debugWithFormat:@"bound to wildcard: %@", self->address]; ++ [self debugWithFormat:@"got local: %@", [self->socket localAddress]]; + +- self->address = [[self->socket localAddress] retain]; ++ self->address = [[self->socket localAddress] retain]; + +- [self logWithFormat:@"bound to kernel assigned address %@: %@", ++ [self logWithFormat:@"bound to kernel assigned address %@: %@", + self->address, self->socket]; ++ } + } +- } + +- [self->socket listenWithBacklog:backlog]; ++ [self->socket listenWithBacklog:backlog]; + +- [[NSNotificationCenter defaultCenter] ++ [[NSNotificationCenter defaultCenter] + addObserver:self selector:@selector(acceptConnection:) +- name:NSFileObjectBecameActiveNotificationName +- object:self->socket]; +- [(WORunLoop *)[WORunLoop currentRunLoop] ++ name:NSFileObjectBecameActiveNotificationName ++ object:self->socket]; ++ ++ [(WORunLoop *)[WORunLoop currentRunLoop] + addFileObject:self->socket + activities:NSPosixReadableActivity + forMode:NSDefaultRunLoopMode]; +- +- [self forkChildren]; ++ } + } ++ + - (void)unregisterForEvents { +- [self killChildren]; +- + [(WORunLoop *)[WORunLoop currentRunLoop] + removeFileObject:self->socket forMode:NSDefaultRunLoopMode]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +@@ -603,52 +522,91 @@ + return _connection; + } + ++- (NGActiveSocket *)_accept { ++ NGActiveSocket *connection; ++ ++ NS_DURING { ++ connection = [self->socket accept]; ++ if (!connection) ++ [self _serverCatched:[self->socket lastException]]; ++ else ++ [self debugWithFormat:@"accepted connection: %@", connection]; ++ } ++ NS_HANDLER { ++ connection = nil; ++ [self _serverCatched:localException]; ++ } ++ NS_ENDHANDLER; ++ ++ return connection; ++} ++ ++- (void)_handleConnection:(NGActiveSocket *)connection { ++ if (connection != nil) { ++ if (self->maxThreadCount <= 1) { ++ NS_DURING ++ [self _handleAcceptedConnection:[connection retain]]; ++ NS_HANDLER ++ [self _serverCatched:localException]; ++ NS_ENDHANDLER; ++ } ++ else { ++ [NSThread detachNewThreadSelector: ++ @selector(_handleAcceptedConnectionInThread:) ++ toTarget:self ++ withObject:[connection retain]]; ++ [self logWithFormat:@"detached new thread for request."]; ++ //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]]; ++ } ++ connection = nil; ++ } ++} ++ ++- (void) acceptControlMessage: (NSNotification *) aNotification ++{ ++ NGActiveSocket *controlSocket, *connection; ++ WOChildMessage message; ++ NSAutoreleasePool *pool; ++ ++ // NSLog (@"received control message"); ++ controlSocket = [aNotification object]; ++ // [self logWithFormat:@"child accepting message from socket: %@", controlSocket]; ++ while (![controlSocket safeReadBytes: &message ++ count: sizeof (WOChildMessage)]) ++ NSLog (@"renotifying watchdog"); ++ if (message == WOChildMessageAccept) { ++ pool = [NSAutoreleasePool new]; ++ connection = [self _accept]; ++ if ([controlSocket safeWriteBytes: &message ++ count: sizeof (WOChildMessage)]) ++ ; ++ [self _handleConnection: connection]; ++ message = WOChildMessageReady; ++ [controlSocket safeWriteBytes: &message count: sizeof (WOChildMessage)]; ++ [pool release]; ++ } ++ else if (message == WOChildMessageShutdown) { ++ [controlSocket safeWriteBytes: &message ++ count: sizeof (WOChildMessage)]; ++ [[WOCoreApplication application] terminate]; ++ } ++} ++ + - (void)acceptConnection:(id)_notification { ++ NGActiveSocket *connection; + #if USE_POOLS + NSAutoreleasePool *pool; +- *(&pool) = [[NSAutoreleasePool alloc] init]; ++ ++ pool = [[NSAutoreleasePool alloc] init]; + #endif + { +- NGActiveSocket *connection; +- +- NS_DURING { +- *(&connection) = (NGActiveSocket *)[self->socket accept]; +- if (connection == nil) +- [self _serverCatched:[self->socket lastException]]; +- else +- [self debugWithFormat:@"accepted connection: %@", connection]; +- } +- NS_HANDLER { +- connection = nil; +- [self _serverCatched:localException]; +- } +- NS_ENDHANDLER; +- +- connection = (NGActiveSocket *)[self _checkAccessOnConnection:connection]; +- +- if (connection != nil) { +- if (self->maxThreadCount <= 1) { +- NS_DURING +- [self _handleAcceptedConnection:[connection retain]]; +- NS_HANDLER +- [self _serverCatched:localException]; +- NS_ENDHANDLER; +- } +- else { +- [NSThread detachNewThreadSelector: +- @selector(_handleAcceptedConnectionInThread:) +- toTarget:self +- withObject:[connection retain]]; +- [self logWithFormat:@"detached new thread for request."]; +- //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]]; +- } +- connection = nil; +- } ++ connection = [self _checkAccessOnConnection:[self _accept]]; ++ [self _handleConnection: connection]; + } + #if USE_POOLS + [pool release]; pool = nil; + #endif +- ++ + if (self->isTerminated) { + if (self->socket) { + [[NSNotificationCenter defaultCenter] +Index: sope-appserver/NGObjWeb/WOCoreApplication.m +=================================================================== +--- sope-appserver/NGObjWeb/WOCoreApplication.m (revision 1664) ++++ sope-appserver/NGObjWeb/WOCoreApplication.m (working copy) +@@ -75,6 +75,43 @@ + NGObjWeb_DECLARE id WOApp = nil; + static NSMutableArray *activeApps = nil; // THREAD + +++ (void)registerUserDefaults { ++ NSDictionary *owDefaults = nil; ++ NSString *apath; ++ ++ apath = [[self class] findNGObjWebResource:@"Defaults" ofType:@"plist"]; ++ if (apath == nil) ++ [self errorWithFormat:@"Cannot find Defaults.plist resource of " ++ @"NGObjWeb library!"]; ++#if HEAVY_DEBUG ++ else ++ [self debugWithFormat:@"Note: loading default defaults: %@", apath]; ++#endif ++ ++ owDefaults = [NSDictionary dictionaryWithContentsOfFile:apath]; ++ if (owDefaults) { ++ [[NSUserDefaults standardUserDefaults] registerDefaults:owDefaults]; ++#if HEAVY_DEBUG ++ [self debugWithFormat:@"did register NGObjWeb defaults: %@\n%@", ++ apath, owDefaults]; ++#endif ++ } ++ else { ++ [self errorWithFormat:@"could not load NGObjWeb defaults: '%@'", ++ apath]; ++ } ++} ++ +++ (void)initialize ++{ ++ static BOOL initialized = NO; ++ ++ if (!initialized) { ++ [self registerUserDefaults]; ++ initialized = YES; ++ } ++} ++ + + (id)application { + if (WOApp == nil) { + [self warnWithFormat:@"%s: some code called +application without an " +@@ -115,33 +152,6 @@ + } + } + +-- (void)registerUserDefaults { +- NSDictionary *owDefaults = nil; +- NSString *apath; +- +- apath = [[self class] findNGObjWebResource:@"Defaults" ofType:@"plist"]; +- if (apath == nil) +- [self errorWithFormat:@"Cannot find Defaults.plist resource of " +- @"NGObjWeb library!"]; +-#if HEAVY_DEBUG +- else +- [self debugWithFormat:@"Note: loading default defaults: %@", apath]; +-#endif +- +- owDefaults = [NSDictionary dictionaryWithContentsOfFile:apath]; +- if (owDefaults) { +- [[NSUserDefaults standardUserDefaults] registerDefaults:owDefaults]; +-#if HEAVY_DEBUG +- [self debugWithFormat:@"did register NGObjWeb defaults: %@\n%@", +- apath, owDefaults]; +-#endif +- } +- else { +- [self errorWithFormat:@"could not load NGObjWeb defaults: '%@'", +- apath]; +- } +-} +- + - (id)init { + #if COCOA_Foundation_LIBRARY + /* +@@ -157,7 +167,6 @@ + NSUserDefaults *ud; + NGLoggerManager *lm; + +- [self registerUserDefaults]; + ud = [NSUserDefaults standardUserDefaults]; + lm = [NGLoggerManager defaultLoggerManager]; + logger = [lm loggerForClass:[self class]]; +@@ -190,6 +199,9 @@ + forSignal:SIGHUP immediatelyNotifyOnSignal:NO]; + } + #endif ++ ++ controlSocket = nil; ++ listeningSocket = nil; + } + return self; + } +@@ -202,9 +214,32 @@ + [self->adaptors release]; + [self->requestLock release]; + [self->lock release]; ++ [self->listeningSocket release]; ++ [self->controlSocket release]; + [super dealloc]; + } + ++/* Watchdog helpers */ ++- (void)setControlSocket: (NGActiveSocket *) newSocket ++{ ++ ASSIGN(self->controlSocket, newSocket); ++} ++ ++- (NGActiveSocket *)controlSocket ++{ ++ return self->controlSocket; ++} ++ ++- (void)setListeningSocket: (NGPassiveSocket *) newSocket ++{ ++ ASSIGN(self->listeningSocket, newSocket); ++} ++ ++- (NGPassiveSocket *)listeningSocket ++{ ++ return self->listeningSocket; ++} ++ + /* NGLogging */ + + + (id)logger { +@@ -225,6 +260,7 @@ + /* STDIO is forbidden in signal handlers !!! no malloc !!! */ + #if 1 + self->cappFlags.isTerminating = 1; ++ [self->listeningSocket close]; + #else + static int termCount = 0; + unsigned pid; +@@ -786,7 +822,9 @@ + id woport; + id addr; + +- woport = [[self userDefaults] objectForKey:@"WOPort"]; ++ woport = [[self userDefaults] objectForKey:@"p"]; ++ if (!woport) ++ woport = [[self userDefaults] objectForKey:@"WOPort"]; + if ([woport isKindOfClass:[NSNumber class]]) + return woport; + woport = [woport stringValue]; --- sope-4.9.r1664.orig/debian/patches/sope-gsmake2.diff +++ sope-4.9.r1664/debian/patches/sope-gsmake2.diff @@ -0,0 +1,3144 @@ +Index: configure +=================================================================== +--- configure (révision 1632) ++++ configure (copie de travail) +@@ -15,8 +15,9 @@ + ARG_NOCREATE=0 + ARG_PREFIX="" + ARG_FRAMEWORK_DIR="" +-ARG_GSMAKE="$GNUSTEP_MAKEFILES" ++ARG_GSMAKE=`gnustep-config --variable=GNUSTEP_MAKEFILES` + ARG_CFGMAKE="$PWD/config.make" ++ARG_FHSMAKE="$PWD/fhs-postinstall.make" + ARG_WITH_GNUSTEP=0 + ARG_WITH_DEBUG=1 + ARG_WITH_STRIP=1 +@@ -30,12 +31,20 @@ + INTERNAL_MAKEDIR="${SOPE_SRCDIR}/.gsmake" + USES_INTERNAL_MAKE=no + ++# detect GNU make, needed at least on *BSD ++make -v 2>/dev/null | grep GNU >/dev/null 2>/dev/null ++if [ $? -eq 0 ];then ++ MAKE=make ++else ++ MAKE=gmake ++fi ++ + # TODO: add pg_config, mysql_config etc! + LINK_SYSLIBDIRS="-L/usr/local/pgsql/lib -L/usr/local/lib -L/usr/lib" + + # ******************** usage ******************** + +-function usage() { ++usage() { + cat <<_ACEOF + \`configure' configures a GNUstep-make based sourcetree for installation. + +@@ -66,7 +75,7 @@ + + # ******************** running ******************** + +-function printParas() { ++printParas() { + echo "Configuration:" + if test $ARG_BEQUIET = 1; then echo " will be quite."; fi + if test $ARG_NOCREATE = 1; then echo " won't create files"; fi +@@ -97,7 +106,7 @@ + echo "" + } + +-function warnOnFHSPrefix() { ++warnOnFHSPrefix() { + cat <<_ACEOFWARN + Warning: you are configuring for a non standard FHS style prefix. + prefix: $ARG_PREFIX +@@ -114,7 +123,7 @@ + _ACEOFWARN + } + +-function setupInternalGSMake() { ++setupInternalGSMake() { + if test -f ${INTERNAL_MAKEDIR}/Library/Makefiles/GNUstep.sh; then + ARG_GSMAKE="${INTERNAL_MAKEDIR}/Library/Makefiles/" + ARG_IS_FHS=1 +@@ -149,7 +158,7 @@ + --with-library-combo="${SETUP_COMBO}" + + echo -n ".. install .." +- make install >>${pregsmdir}/${SETUP_LOGNAME} ++ $MAKE install >>${pregsmdir}/${SETUP_LOGNAME} + + ARG_GSMAKE="${INTERNAL_MAKEDIR}/Library/Makefiles/" + ARG_IS_FHS=1 +@@ -174,7 +183,7 @@ + fi + } + +-function validateGNUstepArgs() { ++validateGNUstepArgs() { + # GNUstep make + if test "x$ARG_GSMAKE" = "x"; then + if test -f $HOME/OGoRoot/Library/Makefiles/GNUstep.sh; then +@@ -203,7 +212,7 @@ + fi + } + +-function setupAppleArgs() { ++setupAppleArgs() { + ARG_WITH_STRIP=0 + if test "x${USES_INTERNAL_MAKE}" = "no"; then + ARG_WITH_GNUSTEP=1 +@@ -218,7 +227,7 @@ + #fi + } + +-function validateArgs() { ++validateArgs() { + # validate prefix (could be better?) + case "x$ARG_PREFIX" in + "x/usr/local"|"x/usr/local/") +@@ -273,7 +282,7 @@ + fi + } + +-function printGNUstepSetup() { ++printGNUstepSetup() { + echo "GNUstep environment:" + echo " system: ${GNUSTEP_SYSTEM_ROOT}" + echo " local: ${GNUSTEP_LOCAL_ROOT}" +@@ -285,11 +294,11 @@ + echo "" + } + +-function cfgwrite() { ++cfgwrite() { + echo "$1" >> $ARG_CFGMAKE + } + +-function genConfigMake() { ++genConfigMake() { + # we ignore the following vars also patches by gstep-make: + # PATH + # DYLD_LIBRARY_PATH +@@ -303,6 +312,8 @@ + echo "# GNUstep environment configuration" > $ARG_CFGMAKE + cfgwrite "# created by: '$CFG_ARGS'" + cfgwrite "" ++ cfgwrite "SOPE_ROOT=`pwd`" ++ cfgwrite "include \${SOPE_ROOT}/Version" + + cfgwrite "# Note: you can override any option as a 'make' parameter, eg:" + cfgwrite "# make debug=yes" +@@ -313,7 +324,27 @@ + #cfgwrite " @echo Local GNUstep config.make is active" + #cfgwrite "" + +- # TODO: should be also write a GNUSTEP_INSTALLATION_DIR / BUNDLE_INSTALL_DIR? ++ # Note: GNUSTEP_TARGET_CPU is not yet available (set by common.make), so we ++ # only have environment variables ++ # Note: we can't set SYSTEM_LIB_DIR in this location, it gets overridden by ++ # common.make ++ UNAME=`uname` ++ if [ "X${UNAME}" = "XLinux" ];then ++ UNAME=`uname -p` ++ if [ ${UNAME} = x86_64 -o ${UNAME} = sparc64 -o ${UNAME} = ppc64 ];then ++ cfgwrite "CGS_LIBDIR_NAME:=lib64" ++ else ++ cfgwrite "CGS_LIBDIR_NAME:=lib" ++ fi ++ else ++ cfgwrite "CGS_LIBDIR_NAME:=lib" ++ fi ++ cfgwrite "ifneq (\$(FHS_INSTALL_ROOT),)" ++ cfgwrite "CONFIGURE_FHS_INSTALL_LIBDIR:=\$(FHS_INSTALL_ROOT)/\$(CGS_LIBDIR_NAME)/" ++ cfgwrite "CONFIGURE_SYSTEM_LIB_DIR += -L\$(CONFIGURE_FHS_INSTALL_LIBDIR)" ++ cfgwrite "endif" ++ cfgwrite "GNUSTEP_INSTALLATION_DOMAIN:=LOCAL" ++ cfgwrite "CONFIGURE_SYSTEM_LIB_DIR += -L/usr/\$(CGS_LIBDIR_NAME)/" + + + if test "x$ARG_FRAMEWORK_DIR" != "x"; then +@@ -325,13 +356,38 @@ + cfgwrite "# configured for FHS install" + cfgwrite "FHS_INSTALL_ROOT:=$ARG_PREFIX" + cfgwrite "" ++ cfgwrite "SOPE_SYSLIBDIR=\${DESTDIR}\${FHS_INSTALL_ROOT}/\$(CGS_LIBDIR_NAME)" ++ cfgwrite "SOPE_LIBDIR=\${SOPE_SYSLIBDIR}/sope-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_SYSSHAREDIR=\${DESTDIR}\${FHS_INSTALL_ROOT}/share" ++ cfgwrite "SOPE_SHAREDIR=\${SOPE_SYSSHAREDIR}/sope-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_DBADAPTORS=\${SOPE_LIBDIR}/dbadaptors" ++ cfgwrite "SOPE_PRODUCTS=\${SOPE_LIBDIR}/products" ++ cfgwrite "SOPE_SAXDRIVERS=\${SOPE_LIBDIR}/saxdrivers" ++ cfgwrite "SOPE_WOXBUILDERS=\${SOPE_LIBDIR}/wox-builders" ++ cfgwrite "SOPE_NGOBJWEB=\${SOPE_SHAREDIR}/ngobjweb" ++ cfgwrite "SOPE_SAXMAPPINGS=\${SOPE_SHAREDIR}/saxmappings" ++ cfgwrite "SOPE_TOOLS=\${DESTDIR}\${FHS_INSTALL_ROOT}/bin" ++ cfgwrite "SOPE_ADMIN_TOOLS=\${DESTDIR}\${FHS_INSTALL_ROOT}/sbin" ++ cfgwrite "" + else + cfgwrite "# configured for GNUstep install" ++ cfgwrite "" ++ cfgwrite "SOPE_SYSLIBDIR=\${GNUSTEP_LIBRARIES}" ++ cfgwrite "SOPE_LIBDIR=\${GNUSTEP_LIBRARY}" ++ cfgwrite "SOPE_DBADAPTORS=\${SOPE_LIBDIR}/GDLAdaptors-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_PRODUCTS=\${SOPE_LIBDIR}/SoProducts-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_SAXDRIVERS=\${SOPE_LIBDIR}/SaxDrivers-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_NGOBJWEB=\${GNUSTEP_RESOURCES}/NGObjWeb" ++ cfgwrite "SOPE_WOXBUILDERS=\${GNUSTEP_LIBRARY}/WOxElemBuilders-\${MAJOR_VERSION}.\${MINOR_VERSION}" ++ cfgwrite "SOPE_SAXMAPPINGS=\${GNUSTEP_LIBRARY}/SaxMappings" ++ cfgwrite "SOPE_TOOLS=\${GNUSTEP_TOOLS}" ++ cfgwrite "SOPE_ADMIN_TOOLS=\${GNUSTEP_ADMIN_TOOLS}" + fi + + if test $ARG_WITH_DEBUG = 1; then + cfgwrite "# configured to produce debugging code"; + cfgwrite "debug:=yes" ++ + else + cfgwrite "# configured to produce non-debugging code"; + cfgwrite "debug:=no" +@@ -358,29 +414,9 @@ + done + cfgwrite "LIBRARY_COMBO=$LIBRARY_COMBO" + cfgwrite "" +- +- # Note: GNUSTEP_TARGET_CPU is not yet available (set by common.make), so we +- # only have environment variables +- # Note: we can't set SYSTEM_LIB_DIR in this location, it gets overridden by +- # common.make +- cfgwrite "ifeq (\$(findstring _64, \$(GNUSTEP_HOST_CPU)), _64)" +- cfgwrite "CONFIGURE_64BIT:=yes" +- cfgwrite "CGS_LIBDIR_NAME:=lib64" +- cfgwrite "else" +- cfgwrite "CGS_LIBDIR_NAME:=lib" +- cfgwrite "endif" +- +- cfgwrite "ifneq (\$(FHS_INSTALL_ROOT),)" +- cfgwrite "CONFIGURE_FHS_INSTALL_LIBDIR:=\$(FHS_INSTALL_ROOT)/\$(CGS_LIBDIR_NAME)/" +- cfgwrite "CONFIGURE_SYSTEM_LIB_DIR += -L\$(CONFIGURE_FHS_INSTALL_LIBDIR)" +- cfgwrite "endif" +- cfgwrite "CONFIGURE_SYSTEM_LIB_DIR += -L/usr/\$(CGS_LIBDIR_NAME)/" +- +- cfgwrite "# avoid a gstep-make warning" +- cfgwrite "PATH:=\$(GNUSTEP_SYSTEM_ROOT)/Tools:\$(PATH)" + } + +-function checkLinking() { ++checkLinking() { + # library-name => $1, type => $2 + local oldpwd=$PWD + local tmpdir=".configure-test-$$" +@@ -388,18 +424,26 @@ + mkdir $tmpdir + cd $tmpdir + cp ../maintenance/dummytool.c . ++ ++ for LIB in $1;do ++ LIBS="$LIBS -l${LIB}" ++ done + + tmpmake="GNUmakefile" +- echo >$tmpmake "include ../config.make" ++ echo >$tmpmake "-include ../config.make" + echo >>$tmpmake "include \$(GNUSTEP_MAKEFILES)/common.make" + echo >>$tmpmake "CTOOL_NAME := linktest" + echo >>$tmpmake "linktest_C_FILES := dummytool.c" +- echo >>$tmpmake "linktest_TOOL_LIBS += -l$1" ++ echo >>$tmpmake "ifeq (\$(findstring openbsd, \$(GNUSTEP_HOST_OS)), openbsd)" ++ echo >>$tmpmake "linktest_TOOL_LIBS += $LIBS -liconv" ++ echo >>$tmpmake "else" ++ echo >>$tmpmake "linktest_TOOL_LIBS += $LIBS" ++ echo >>$tmpmake "endif" + echo >>$tmpmake "SYSTEM_LIB_DIR += \$(CONFIGURE_SYSTEM_LIB_DIR)" + echo >>$tmpmake "SYSTEM_LIB_DIR += ${LINK_SYSLIBDIRS}" + echo >>$tmpmake "include \$(GNUSTEP_MAKEFILES)/ctool.make" + +- make -s messages=yes -f $tmpmake linktest >out.log 2>err.log ++ $MAKE -s messages=yes -f $tmpmake linktest >out.log 2>err.log + LINK_RESULT=$? + + if test $LINK_RESULT = 0; then +@@ -420,18 +464,22 @@ + rm -rf $tmpdir + } + +-function checkDependencies() { ++checkDependencies() { + cfgwrite "" + cfgwrite "# library dependencies" + checkLinking "xml2" optional; + checkLinking "ldap" optional; +- checkLinking "ssl" required; # TODO: make optional ++ if [ `uname` = "OpenBSD" ];then ++ checkLinking "ssl crypto" required; # TODO: make optional ++ else ++ checkLinking "ssl" required; # TODO: make optional ++ fi + checkLinking "pq" optional; + checkLinking "sqlite3" optional; + checkLinking "mysqlclient" optional; + } + +-function runIt() { ++runIt() { + if test $ARG_BEQUIET != 1; then + printParas; + fi +@@ -459,11 +507,11 @@ + + # ******************** options ******************** + +-function extractFuncValue() { ++extractFuncValue() { + VALUE="`echo "$1" | sed "s/[^=]*=//g"`" + } + +-function processOption() { ++processOption() { + case "x$1" in + "x--help"|"x-h") + usage; +@@ -518,7 +566,7 @@ + # load GNUstep environment + validateGNUstepArgs + # first we load the GNUstep.sh environment +-source $DARG_GNUSTEP_SH ++. $DARG_GNUSTEP_SH + if test $ARG_BEQUIET != 1; then + printGNUstepSetup; + fi +Index: sope-ldap/samples/GNUmakefile +=================================================================== +--- sope-ldap/samples/GNUmakefile (révision 1632) ++++ sope-ldap/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = \ +@@ -9,8 +9,11 @@ + ldapchkpwd \ + + ldapls_OBJC_FILES = ldapls.m ++ldapls_INSTALL_DIR = $(SOPE_TOOLS)/ + ldap2dsml_OBJC_FILES = ldap2dsml.m ++ldap2dsml_INSTALL_DIR = $(SOPE_TOOLS)/ + ldapchkpwd_OBJC_FILES = ldapchkpwd.m ++ldapchkpwd_INSTALL_DIR = $(SOPE_TOOLS)/ + + #TOOL_NAME = #pwd-check + #pwd-check_OBJC_FILES = pwd-check.m +@@ -19,4 +22,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-ldap/NGLdap/GNUmakefile +=================================================================== +--- sope-ldap/NGLdap/GNUmakefile (révision 1632) ++++ sope-ldap/NGLdap/GNUmakefile (copie de travail) +@@ -1,11 +1,9 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ./Version + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ifneq ($(frameworks),yes) + LIBRARY_NAME = libNGLdap + else +@@ -15,7 +13,8 @@ + libNGLdap_PCH_FILE = common.h + libNGLdap_HEADER_FILES_DIR = . + libNGLdap_HEADER_FILES_INSTALL_DIR = /NGLdap +-libNGLdap_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGLdap_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGLdap_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGLdap_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGLdap_HEADER_FILES = \ +@@ -61,10 +60,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-ldap/GNUmakefile +=================================================================== +--- sope-ldap/GNUmakefile (révision 1632) ++++ sope-ldap/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-ldap +Index: GNUmakefile +=================================================================== +--- GNUmakefile (révision 1632) ++++ GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ./config.make ++include ./config.make + + ifeq ($(GNUSTEP_MAKEFILES),) + +@@ -35,8 +35,6 @@ + include $(GNUSTEP_MAKEFILES)/aggregate.make + -include $(GNUSTEP_MAKEFILES)/GNUmakefile.postamble + +-include ./Version +- + endif + + distclean :: +Index: sope-gdl1/PostgreSQL/GNUmakefile.preamble +=================================================================== +--- sope-gdl1/PostgreSQL/GNUmakefile.preamble (révision 1632) ++++ sope-gdl1/PostgreSQL/GNUmakefile.preamble (copie de travail) +@@ -27,7 +27,7 @@ + ifeq ($(frameworks),yes) + BUNDLE_INSTALL_DIR := $(FRAMEWORK_INSTALL_DIR)/GDLAccess.framework/Resources/GDLAdaptors/ + else +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/GDLAdaptors-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_DBADAPTORS)/ + endif + + +Index: sope-gdl1/PostgreSQL/GNUmakefile +=================================================================== +--- sope-gdl1/PostgreSQL/GNUmakefile (révision 1632) ++++ sope-gdl1/PostgreSQL/GNUmakefile (copie de travail) +@@ -22,7 +22,7 @@ + # If not, write to the Free Software Foundation, + # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -70,4 +70,3 @@ + include $(GNUSTEP_MAKEFILES)/bundle.make + #include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +-include fhs.make +Index: sope-gdl1/SQLite3/GNUmakefile.preamble +=================================================================== +--- sope-gdl1/SQLite3/GNUmakefile.preamble (révision 1632) ++++ sope-gdl1/SQLite3/GNUmakefile.preamble (copie de travail) +@@ -27,7 +27,7 @@ + ifeq ($(frameworks),yes) + BUNDLE_INSTALL_DIR := $(FRAMEWORK_INSTALL_DIR)/GDLAccess.framework/Resources/GDLAdaptors/ + else +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/GDLAdaptors-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_DBADAPTORS)/ + endif + + +Index: sope-gdl1/SQLite3/GNUmakefile +=================================================================== +--- sope-gdl1/SQLite3/GNUmakefile (révision 1632) ++++ sope-gdl1/SQLite3/GNUmakefile (copie de travail) +@@ -22,7 +22,7 @@ + # If not, write to the Free Software Foundation, + # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -67,4 +67,3 @@ + include $(GNUSTEP_MAKEFILES)/tool.make + endif + -include GNUmakefile.postamble +-include fhs.make +Index: sope-gdl1/FrontBase2/GNUmakefile +=================================================================== +--- sope-gdl1/FrontBase2/GNUmakefile (révision 1632) ++++ sope-gdl1/FrontBase2/GNUmakefile (copie de travail) +@@ -22,7 +22,7 @@ + # If not, write to the Free Software Foundation, + # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + CAN_COMPILE_FB = \ +@@ -30,8 +30,6 @@ + + ifeq ($(CAN_COMPILE_FB),yes) + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + BUNDLE_NAME = FrontBase2 + + FrontBase2_OBJC_FILES = \ +@@ -51,7 +49,7 @@ + FrontBase2_RESOURCE_FILES = Info.plist Version + + BUNDLE_INSTALL = FrontBase2 +-BUNDLE_INSTALL_DIR = $(GNUSTEP_SYSTEM_ROOT)/Libraries/Adaptors ++BUNDLE_INSTALL_DIR = $(SOPE_DBADAPTORS)/ + + # Use .gdladaptor as the bundle extension + BUNDLE_EXTENSION = .gdladaptor +Index: sope-gdl1/MySQL/GNUmakefile.preamble +=================================================================== +--- sope-gdl1/MySQL/GNUmakefile.preamble (révision 1632) ++++ sope-gdl1/MySQL/GNUmakefile.preamble (copie de travail) +@@ -27,7 +27,7 @@ + ifeq ($(frameworks),yes) + BUNDLE_INSTALL_DIR := $(FRAMEWORK_INSTALL_DIR)/GDLAccess.framework/Resources/GDLAdaptors/ + else +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/GDLAdaptors-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_DBADAPTORS)/ + endif + + +Index: sope-gdl1/MySQL/GNUmakefile +=================================================================== +--- sope-gdl1/MySQL/GNUmakefile (révision 1632) ++++ sope-gdl1/MySQL/GNUmakefile (copie de travail) +@@ -22,7 +22,7 @@ + # If not, write to the Free Software Foundation, + # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -67,4 +67,3 @@ + include $(GNUSTEP_MAKEFILES)/tool.make + endif + -include GNUmakefile.postamble +-include fhs.make +Index: sope-gdl1/GNUmakefile +=================================================================== +--- sope-gdl1/GNUmakefile (révision 1632) ++++ sope-gdl1/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-gdl1 +Index: sope-gdl1/GDLAccess/GNUmakefile.preamble +=================================================================== +--- sope-gdl1/GDLAccess/GNUmakefile.preamble (révision 1632) ++++ sope-gdl1/GDLAccess/GNUmakefile.preamble (copie de travail) +@@ -21,17 +21,12 @@ + -I$(SOPE_ROOT)/sope-core/NGExtensions/ + + +-# Parameters for EOAdaptor lookup + +-ifneq ($(FHS_INSTALL_ROOT),) +-ADDITIONAL_CPPFLAGS += -DFHS_INSTALL_ROOT=\@\"$(FHS_INSTALL_ROOT)\" ++ifneq ($(CGS_LIBDIR_NAME),) ++ADDITIONAL_CPPFLAGS += -DCGS_LIBDIR_NAME=\@\"$(CGS_LIBDIR_NAME)\" + endif + +-ifeq ($(CONFIGURE_64BIT),yes) +-ADDITIONAL_CPPFLAGS += -DCONFIGURE_64BIT=1 +-endif + +- + # dependencies + + libGDLAccess_LIBRARIES_DEPEND_UPON += -lEOControl +Index: sope-gdl1/GDLAccess/GNUmakefile +=================================================================== +--- sope-gdl1/GDLAccess/GNUmakefile (révision 1632) ++++ sope-gdl1/GDLAccess/GNUmakefile (copie de travail) +@@ -1,12 +1,10 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + -include ../Version + -include ./Version + +-GNUSTEP_INSTALLATION_DIR = ${GNUSTEP_LOCAL_ROOT} +- + ifneq ($(frameworks),yes) + LIBRARY_NAME = libGDLAccess + else +@@ -14,7 +12,8 @@ + endif + + libGDLAccess_PCH_FILE = common.h +-libGDLAccess_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libGDLAccess_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libGDLAccess_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libGDLAccess_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libGDLAccess_DLL_DEF = libGDLAccess.def +@@ -123,6 +122,8 @@ + connect-EOAdaptor_OBJC_FILES = connect-EOAdaptor.m + load-EOAdaptor_PCH_FILE = common.h + connect-EOAdaptor_PCH_FILE = common.h ++load-EOAdaptor_INSTALL_DIR = $(SOPE_TOOLS)/ ++connect-EOAdaptor_INSTALL_DIR = $(SOPE_TOOLS)/ + + + # framework support +@@ -136,6 +137,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else +@@ -143,4 +147,3 @@ + endif + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +-include fhs.make +Index: sope-gdl1/GDLAccess/EOAdaptor.h +=================================================================== +--- sope-gdl1/GDLAccess/EOAdaptor.h (révision 1632) ++++ sope-gdl1/GDLAccess/EOAdaptor.h (copie de travail) +@@ -62,11 +62,14 @@ + + (id)adaptorWithModel:(EOModel *)aModel; + + (id)adaptorWithName:(NSString *)aName; + + (id)adaptorForURL:(id)_url; +++ (NSString *)libraryDriversSubDir; + - (id)initWithName:(NSString *)aName; + + /* Getting an adaptor's name */ + - (NSString*)name; + ++/* Get the library subdir name */ ++ + /* Setting connection information */ + - (void)setConnectionDictionary:(NSDictionary*)aDictionary; + - (NSDictionary*)connectionDictionary; +Index: sope-gdl1/GDLAccess/EOAdaptor.m +=================================================================== +--- sope-gdl1/GDLAccess/EOAdaptor.m (révision 1632) ++++ sope-gdl1/GDLAccess/EOAdaptor.m (copie de travail) +@@ -53,14 +53,23 @@ + + (NSArray *)adaptorSearchPathes { + // TODO: add support for Cocoa + static NSArray *searchPathes = nil; +- NSDictionary *env; + NSMutableArray *ma; + id tmp; + + if (searchPathes != nil) return searchPathes; + ++ ma = [NSMutableArray arrayWithCapacity:8]; ++ ++#if GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory, *suffix; ++ suffix = [self libraryDriversSubDir]; ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent: suffix]]; ++#else ++ NSDictionary *env; + env = [[NSProcessInfo processInfo] environment]; +- ma = [NSMutableArray arrayWithCapacity:8]; + + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) + tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; +@@ -79,10 +88,11 @@ + [ma addObject:tmp]; + } + } ++#endif + + tmp = [NSString stringWithFormat: +-#if CONFIGURE_64BIT +- @"/lib64/sope-%i.%i/dbadaptors", ++#ifdef CGS_LIBDIR_NAME ++ [CGS_LIBDIR_NAME stringByAppendingString:@"/sope-%i.%i/dbadaptors"], + #else + @"/lib/sope-%i.%i/dbadaptors", + #endif +@@ -92,9 +102,8 @@ + [ma addObject:[FHS_INSTALL_ROOT stringByAppendingPathComponent:tmp]]; + #endif + +- [ma addObject:[@"/usr/local" stringByAppendingString:tmp]]; +- [ma addObject:[@"/usr" stringByAppendingString:tmp]]; +- ++ [ma addObject:[@"/usr/local/" stringByAppendingString:tmp]]; ++ [ma addObject:[@"/usr/" stringByAppendingString:tmp]]; + searchPathes = [ma copy]; + if ([searchPathes count] == 0) + NSLog(@"%s: empty library search path !", __PRETTY_FUNCTION__); +@@ -213,6 +222,11 @@ + return _scheme; + } + +++ (NSString *)libraryDriversSubDir { ++ return [NSString stringWithFormat:@"GDLAdaptors-%i.%i", ++ GDL_MAJOR_VERSION, GDL_MINOR_VERSION]; ++} ++ + - (NSDictionary *)connectionDictionaryForNSURL:(NSURL *)_url { + /* + "Database URLs" +Index: sope-gdl1/GDLAccess/FoundationExt/GNUmakefile +=================================================================== +--- sope-gdl1/GDLAccess/FoundationExt/GNUmakefile (révision 1632) ++++ sope-gdl1/GDLAccess/FoundationExt/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../../Version + include ../Version +Index: sope-gdl1/GDLAccess/common.h +=================================================================== +--- sope-gdl1/GDLAccess/common.h (révision 1632) ++++ sope-gdl1/GDLAccess/common.h (copie de travail) +@@ -42,7 +42,7 @@ + #import + #import + +-#if !(COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY) ++#if !(COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY || GNUSTEP_BASE_LIBRARY) + # import + #endif + +Index: sope-gdl1/Oracle8/GNUmakefile +=================================================================== +--- sope-gdl1/Oracle8/GNUmakefile (révision 1632) ++++ sope-gdl1/Oracle8/GNUmakefile (copie de travail) +@@ -19,7 +19,7 @@ + # License along with this library; if not, write to the Free Software + # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + # +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -51,7 +51,7 @@ + ifeq ($(frameworks),yes) + BUNDLE_INSTALL_DIR := $(FRAMEWORK_INSTALL_DIR)/GDLAccess.framework/Resources/GDLAdaptors/ + else +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/GDLAdaptors-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_DBADAPTORS)/ + endif + + Oracle8_OBJC_FILES = \ +Index: sope-mime/NGImap4/GNUmakefile +=================================================================== +--- sope-mime/NGImap4/GNUmakefile (révision 1632) ++++ sope-mime/NGImap4/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + +@@ -63,7 +63,10 @@ + NGImap4MailboxInfo.m \ + NGImap4ConnectionManager.m \ + +--include GNUmakefile.preamble ++include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/subproject.make + else +Index: sope-mime/samples/GNUmakefile +=================================================================== +--- sope-mime/samples/GNUmakefile (révision 1632) ++++ sope-mime/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = \ +@@ -14,16 +14,24 @@ + imapcontest \ + + imapquota_OBJC_FILES = ImapQuotaTool.m ImapTool.m imapquota.m ++imapquota_INSTALL_DIR = $(SOPE_TOOLS) + imapacl_OBJC_FILES = ImapQuotaTool.m ImapTool.m imapacl.m ++imapctl_INSTALL_DIR = $(SOPE_TOOLS) + imapget_OBJC_FILES = ImapTool.m imapget.m ++imapget_INSTALL_DIR = $(SOPE_TOOLS) + imap_tool_OBJC_FILES = imap_tool.m ++imap_tool_INSTALL_DIR = $(SOPE_TOOLS) + mime2xml_OBJC_FILES = Mime2XmlTool.m mime2xml.m ++mime2xml_INSTALL_DIR = $(SOPE_TOOLS) + imapls_OBJC_FILES = ImapTool.m ImapListTool.m imapls.m ++imapls_INSTALL_DIR = $(SOPE_TOOLS) + test_qpdecode_OBJC_FILES = test_qpdecode.m ++test_qpdecode_INSTALL_DIR= $(SOPE_TOOLS) + sievetool_OBJC_FILES = sievetool.m ++sievetool_INSTALL_DIR = $(SOPE_TOOLS) + imapcontest_OBJC_FILES = imapcontest.m ++imapcontest_INSTALL_DIR = $(SOPE_TOOLS) + + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-mime/NGMail/GNUmakefile +=================================================================== +--- sope-mime/NGMail/GNUmakefile (révision 1632) ++++ sope-mime/NGMail/GNUmakefile (copie de travail) +@@ -1,10 +1,8 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ifneq ($(frameworks),yes) + SUBPROJECT_NAME = NGMail + else +@@ -55,6 +53,9 @@ + NSData+MimeQP.m \ + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/subproject.make + else +Index: sope-mime/GNUmakefile +=================================================================== +--- sope-mime/GNUmakefile (révision 1632) ++++ sope-mime/GNUmakefile (copie de travail) +@@ -1,11 +1,9 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ./Version + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ifneq ($(frameworks),yes) + LIBRARY_NAME = libNGMime + else +@@ -14,7 +12,8 @@ + + libNGMime_HEADER_FILES_DIR = . + libNGMime_HEADER_FILES_INSTALL_DIR = /NGMime +-libNGMime_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGMime_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGMime_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGMime_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + ifneq ($(frameworks),yes) +@@ -35,6 +34,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else +@@ -42,7 +44,6 @@ + include $(GNUSTEP_MAKEFILES)/aggregate.make + endif + -include GNUmakefile.postamble +--include fhs.make + + + # package +Index: sope-mime/NGMime/GNUmakefile.preamble +=================================================================== +--- sope-mime/NGMime/GNUmakefile.preamble (révision 1632) ++++ sope-mime/NGMime/GNUmakefile.preamble (copie de travail) +@@ -5,6 +5,15 @@ + -DLIBRARY_MINOR_VERSION=${MINOR_VERSION} \ + -DLIBRARY_SUBMINOR_VERSION=${SUBMINOR_VERSION} \ + ++ifeq ($(patsubstr GNU/%,glibc,$(shell uname -o)),glibc) ++ADDITIONAL_CPPFLAGS += \ ++ -DHAVE_STRNDUP ++endif ++ ++ifneq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) ++ ADDITIONAL_CPPFLAGS += -DHAVE_STRNDUP ++endif ++ + NGMime_INCLUDE_DIRS += \ + -I.. -I../.. \ + -I../../sope-core/NGStreams/ \ +Index: sope-mime/NGMime/GNUmakefile +=================================================================== +--- sope-mime/NGMime/GNUmakefile (révision 1632) ++++ sope-mime/NGMime/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + +@@ -76,5 +76,8 @@ + NGMimeRfc822BodyGenerator.m \ + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + include $(GNUSTEP_MAKEFILES)/subproject.make + -include GNUmakefile.postamble +Index: sope-core/NGExtensions/NGExtensions/NGResourceLocator.h +=================================================================== +--- sope-core/NGExtensions/NGExtensions/NGResourceLocator.h (révision 1632) ++++ sope-core/NGExtensions/NGExtensions/NGResourceLocator.h (copie de travail) +@@ -52,23 +52,54 @@ + int reserved:29; + } flags; + } +- ++/* The 'GNUstepPath' is a string describing the required path. This ++ * is the relative location of the path in a standard GNUstep ++ * hierarchy when a standard GNUstep hierarchy is being used; but if ++ * gnustep-base (which supports arbitrary filesystem layouts) is being ++ * used, the path is heuristically mapped to the standard paths ++ * accepted by NSSearchPathForDirectoriesInDomains using the following ++ * logic: ++ * ++ * "Library/WebApplications" --> GSWebApplicationsDirectory ++ * "Library/Libraries" --> GSLibrariesDirectory ++ * "Tools" --> GSToolsDirectory ++ * "Tools/Admin" --> GSAdminToolsDirectory ++ * "Applications" --> GSApplicationsDirectory ++ * "Applications/Admin" --> GSAdminApplicationsDirectory ++ * "Library/xxx" --> NSLibraryDirectory/xxx ++ * "yyy" --> NSLibraryDirectory/yyy ++ * ++ * In the last two cases 'xxx' and 'yyy' are arbitrary strings/paths ++ * that don't match anything else. Eg, if you create an ++ * NGResourceLocators to look up files in "Library/Resources" you will ++ * get one that looks them up in NSLibraryDirectory/Resources (which ++ * means a list of directories containing ++ * GNUSTEP_USER_LIBRARY/Resources, GNUSTEP_LOCAL_LIBRARY/Resources, ++ * GNUSTEP_NETWORK_LIBRARY/Resources, ++ * GNUSTEP_SYSTEM_LIBRARY/Resources). ++ */ + + (id)resourceLocatorForGNUstepPath:(NSString *)_path fhsPath:(NSString *)_fhs; + - (id)initWithGNUstepPath:(NSString *)_path fhsPath:(NSString *)_fhs; + + /* resource pathes */ + ++/* It's not a good idea to access these directly if you want portable ++ * code. More logical to use directly the 'operations' lookup methods ++ * below which encapsulate all the internal filesystem details. ++ */ + - (NSArray *)gsRootPathes; /* GNUSTEP_PATHPREFIX_LIST or MacOSX */ + - (NSArray *)fhsRootPathes; + - (NSArray *)searchPathes; + + /* operations */ + ++/* These are public and work across all types of filesystems, it's how you find resources. */ + - (NSString *)lookupFileWithName:(NSString *)_name; + - (NSString *)lookupFileWithName:(NSString *)_name extension:(NSString *)_ext; + + - (NSArray *)lookupAllFilesWithExtension:(NSString *)_ext + doReturnFullPath:(BOOL)_withPath; ++/* End public */ + + @end + +Index: sope-core/NGExtensions/NGBundleManager.m +=================================================================== +--- sope-core/NGExtensions/NGBundleManager.m (révision 1632) ++++ sope-core/NGExtensions/NGBundleManager.m (copie de travail) +@@ -332,10 +332,7 @@ + } + + - (void)_addGNUstepPathsToPathArray:(NSMutableArray *)_paths { +-#if !GNUSTEP +-#else +- // TODO: whats that supposed to do? +- // TODO: replace with proper path locator function! ++ /* Old code for old gstep-make and gstep-base. */ + NSDictionary *env; + NSString *p; + unsigned i, count; +@@ -355,7 +352,19 @@ + + if (p) [self->bundleSearchPaths addObject:p]; + } +-#endif ++ ++ /* New code for new gstep-make and gstep-base. */ ++ tmp = NSStandardLibraryPaths(); ++ { ++ NSEnumerator *e = [tmp objectEnumerator]; ++ while ((tmp = [e nextObject]) != nil) { ++ tmp = [tmp stringByAppendingPathComponent:@"Bundles"]; ++ if ([self->bundleSearchPaths containsObject:tmp]) ++ continue; ++ ++ [self->bundleSearchPaths addObject:tmp]; ++ } ++ } + } + + - (void)_setupBundleSearchPathes { +Index: sope-core/NGExtensions/FdExt.subproj/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/FdExt.subproj/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/FdExt.subproj/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../common.make + + SUBPROJECT_NAME = FdExt +Index: sope-core/NGExtensions/XmlExt.subproj/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/XmlExt.subproj/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/XmlExt.subproj/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../common.make + + SUBPROJECT_NAME = XmlExt +Index: sope-core/NGExtensions/EOExt.subproj/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/EOExt.subproj/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/EOExt.subproj/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../common.make + + SUBPROJECT_NAME = EOExt +Index: sope-core/NGExtensions/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -11,7 +11,8 @@ + + libNGExtensions_PCH_FILE = common.h + libNGExtensions_DLL_DEF = libNGExtensions.def +-libNGExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGExtensions_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGExtensions_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGExtensions_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGExtensions_HEADER_FILES_DIR = ./NGExtensions +@@ -157,10 +158,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-core/NGExtensions/NGResourceLocator.m +=================================================================== +--- sope-core/NGExtensions/NGResourceLocator.m (révision 1632) ++++ sope-core/NGExtensions/NGResourceLocator.m (copie de travail) +@@ -43,7 +43,11 @@ + return self; + } + - (id)init { ++#if GNUSTEP_BASE_LIBRARY ++ return [self initWithGNUstepPath:@"Resources" fhsPath:@"share"]; ++#else + return [self initWithGNUstepPath:@"Library/Resources" fhsPath:@"share"]; ++#endif + } + + - (void)dealloc { +@@ -93,19 +97,30 @@ + NSString *p; + + ma = [NSMutableArray arrayWithCapacity:6]; +- +- e = ([self->gsSubPath length] > 0) +- ? [[self gsRootPathes] objectEnumerator] +- : (NSEnumerator *)nil; +- while ((p = [e nextObject]) != nil) { +- p = [p stringByAppendingPathComponent:self->gsSubPath]; +- if ([ma containsObject:p]) +- continue; ++ ++ if ([self->gsSubPath length] > 0) { + +- if (![self->fileManager fileExistsAtPath:p]) +- continue; ++#if GNUSTEP_BASE_LIBRARY ++ NSString *directory; + +- [ma addObject:p]; ++ e = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [e nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent:self->gsSubPath]]; ++#else ++ ++ /* Old hack using GNUSTEP_PATHLIST. Should be removed at some point. */ ++ e = [[self gsRootPathes] objectEnumerator]; ++ while ((p = [e nextObject]) != nil) { ++ p = [p stringByAppendingPathComponent:self->gsSubPath]; ++ if ([ma containsObject:p]) ++ continue; ++ ++ if (![self->fileManager fileExistsAtPath:p]) ++ continue; ++ ++ [ma addObject:p]; ++ } ++#endif + } + + e = ([self->fhsSubPath length] > 0) +Index: sope-core/NGExtensions/NGLogging.subproj/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/NGLogging.subproj/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/NGLogging.subproj/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../common.make + + SUBPROJECT_NAME = NGLogging +Index: sope-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile +=================================================================== +--- sope-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile (révision 1632) ++++ sope-core/NGExtensions/NGRuleEngine.subproj/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../common.make + + SUBPROJECT_NAME = NGRuleEngine +Index: sope-core/GNUmakefile +=================================================================== +--- sope-core/GNUmakefile (révision 1632) ++++ sope-core/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-core +@@ -32,4 +32,4 @@ + # package + + macosx-pkg :: all +- ../maintenance/make-osxpkg.sh sope-core ++ ../maintenance/make-osxpkg.sh $(PACKAGE_NAME) +Index: sope-core/NGStreams/GNUmakefile.preamble +=================================================================== +--- sope-core/NGStreams/GNUmakefile.preamble (révision 1632) ++++ sope-core/NGStreams/GNUmakefile.preamble (copie de travail) +@@ -38,7 +38,11 @@ + endif + + ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64) ++ifeq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) ++SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib ++else + SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64 ++endif + else + SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib + endif +Index: sope-core/NGStreams/GNUmakefile +=================================================================== +--- sope-core/NGStreams/GNUmakefile (révision 1632) ++++ sope-core/NGStreams/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + include ./Version + +@@ -12,7 +12,8 @@ + + libNGStreams_PCH_FILE = common.h + libNGStreams_DLL_DEF = libNGStreams.def +-libNGStreams_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGStreams_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGStreams_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGStreams_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGStreams_HEADER_FILES_DIR = NGStreams +@@ -106,10 +107,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-core/samples/GNUmakefile +=================================================================== +--- sope-core/samples/GNUmakefile (révision 1632) ++++ sope-core/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = \ +@@ -36,4 +36,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-core/EOControl/GNUmakefile +=================================================================== +--- sope-core/EOControl/GNUmakefile (révision 1632) ++++ sope-core/EOControl/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -11,7 +11,8 @@ + + libEOControl_PCH_FILE = common.h + libEOControl_DLL_DEF = libEOControl.def +-libEOControl_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libEOControl_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libEOControl_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libEOControl_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libEOControl_HEADER_FILES_DIR = . +@@ -73,10 +74,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-core/common.make +=================================================================== +--- sope-core/common.make (révision 1632) ++++ sope-core/common.make (copie de travail) +@@ -6,8 +6,6 @@ + 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 +Index: sope-core/EOCoreData/GNUmakefile +=================================================================== +--- sope-core/EOCoreData/GNUmakefile (révision 1632) ++++ sope-core/EOCoreData/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -10,7 +10,8 @@ + endif + + libEOCoreData_PCH_FILE = common.h +-libEOCoreData_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libEOCoreData_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libEOCoreData_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libEOCoreData_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libEOCoreData_HEADER_FILES_DIR = . +@@ -67,10 +68,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: xmlrpc_call/GNUmakefile +=================================================================== +--- xmlrpc_call/GNUmakefile (révision 1632) ++++ xmlrpc_call/GNUmakefile (copie de travail) +@@ -1,10 +1,11 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + + TOOL_NAME = xmlrpc_call ++xmlrpc_call_INSTALL_DIR = $(SOPE_TOOLS) + + xmlrpc_call_PCH_FILE = common.h + +@@ -17,7 +18,6 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make + + macosx-pkg :: + # do not build a pkg just for this tool +Index: xmlrpc_call/GNUmakefile.preamble +=================================================================== +--- xmlrpc_call/GNUmakefile.preamble (révision 1632) ++++ xmlrpc_call/GNUmakefile.preamble (copie de travail) +@@ -1,5 +1,6 @@ + # compilation settings + ++include ../config.make + SOPE_ROOT=.. + CORE_ROOT=$(SOPE_ROOT)/sope-core + APPSERVER_ROOT=$(SOPE_ROOT)/sope-appserver +@@ -57,14 +58,13 @@ + $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir)) + endif + +-ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64) +-SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64 ++ifneq ($(CGS_LIBDIR_NAME),) ++SYSTEM_LIB_DIR += -L/usr/local/$(CGS_LIBDIR_NAME) -L/usr/$(CGS_LIBDIR_NAME) + else + SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib + endif + +- + # OS dependend stuff +-ifeq ($(findstring openbsd3, $(GNUSTEP_HOST_OS)), openbsd3) ++ifeq ($(findstring openbsd, $(GNUSTEP_HOST_OS)), openbsd) + xmlrpc_call_TOOL_LIBS += -liconv + endif +Index: sope-xml/libxmlSAXDriver/GNUmakefile +=================================================================== +--- sope-xml/libxmlSAXDriver/GNUmakefile (révision 1632) ++++ sope-xml/libxmlSAXDriver/GNUmakefile (copie de travail) +@@ -1,13 +1,13 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version + + BUNDLE_NAME = libxmlSAXDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_SAXDRIVERS) + + libxmlSAXDriver_PCH_FILE = common.h + +@@ -24,4 +24,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/bundle.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/DOM/GNUmakefile.preamble +=================================================================== +--- sope-xml/DOM/GNUmakefile.preamble (révision 1632) ++++ sope-xml/DOM/GNUmakefile.preamble (copie de travail) +@@ -1,10 +1,13 @@ + # compilation settings + ++include ./Version ++ + libDOM_HEADER_FILES_DIR = . + libDOM_HEADER_FILES_INSTALL_DIR = /DOM +-libDOM_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libDOM_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libDOM_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libDOM_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) +-DOM_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++DOM_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) + DOM_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + +Index: sope-xml/DOM/GNUmakefile +=================================================================== +--- sope-xml/DOM/GNUmakefile (révision 1632) ++++ sope-xml/DOM/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -98,10 +98,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/ChangeLogSaxDriver/GNUmakefile +=================================================================== +--- sope-xml/ChangeLogSaxDriver/GNUmakefile (révision 1632) ++++ sope-xml/ChangeLogSaxDriver/GNUmakefile (copie de travail) +@@ -1,13 +1,13 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + -include ../../Version + -include ./Version + + BUNDLE_NAME = ChangeLogSaxDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = ${SOPE_SAXDRIVERS}/ + + ChangeLogSaxDriver_OBJC_FILES = \ + ChangeLogSaxDriver.m \ +@@ -20,4 +20,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/bundle.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/GNUmakefile +=================================================================== +--- sope-xml/GNUmakefile (révision 1632) ++++ sope-xml/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-xml +Index: sope-xml/SaxObjC/SaxXMLReaderFactory.m +=================================================================== +--- sope-xml/SaxObjC/SaxXMLReaderFactory.m (révision 1632) ++++ sope-xml/SaxObjC/SaxXMLReaderFactory.m (copie de travail) +@@ -137,11 +137,19 @@ + + - (void)addSearchPathesForGNUstepEnv:(NSMutableArray *)ma { + /* for libFoundation */ ++#if GNUSTEP_BASE_LIBRARY ++NSEnumerator *libraryPaths; ++ NSString *directory, *suffix; ++ ++ suffix = [self libraryDriversSubDir]; ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent: suffix]]; ++#else ++ NSString *subdir; ++ NSEnumerator *e; + NSDictionary *env; +- NSEnumerator *e; +- NSString *subdir; + id tmp; +- + env = [[NSProcessInfo processInfo] environment]; + + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) +@@ -159,6 +167,7 @@ + + [ma addObject:tmp]; + } ++#endif + } + + - (NSArray *)saxReaderSearchPathes { +@@ -182,8 +191,8 @@ + /* FHS fallback */ + + tmp = [[NSString alloc] initWithFormat: +-#if CONFIGURE_64BIT +- @"lib64/sope-%i.%i/saxdrivers/", ++#ifdef CGS_LIBDIR_NAME ++ [CGS_LIBDIR_NAME stringByAppendingString:@"/sope-%i.%i/saxdrivers/"], + #else + @"lib/sope-%i.%i/saxdrivers/", + #endif +Index: sope-xml/SaxObjC/SaxObjectModel.h +=================================================================== +--- sope-xml/SaxObjC/SaxObjectModel.h (révision 1632) ++++ sope-xml/SaxObjC/SaxObjectModel.h (copie de travail) +@@ -34,6 +34,7 @@ + + + (id)modelWithName:(NSString *)_name; + + (id)modelWithContentsOfFile:(NSString *)_path; +++ (NSString *)libraryDriversSubDir; + + - (id)initWithDictionary:(NSDictionary *)_dict; + +Index: sope-xml/SaxObjC/SaxObjectModel.m +=================================================================== +--- sope-xml/SaxObjC/SaxObjectModel.m (révision 1632) ++++ sope-xml/SaxObjC/SaxObjectModel.m (copie de travail) +@@ -67,12 +67,12 @@ + if (searchPathes == nil) { + NSMutableArray *ma; + NSDictionary *env; +- id tmp; + + env = [[NSProcessInfo processInfo] environment]; + ma = [NSMutableArray arrayWithCapacity:6]; + + #if COCOA_Foundation_LIBRARY ++ id tmp; + tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, + NSAllDomainsMask, + YES); +@@ -86,7 +86,16 @@ + [ma addObject:tmp]; + } + } ++#elif GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory, *suffix; ++ ++ suffix = [self libraryDriversSubDir]; ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent: suffix]]; + #else ++ id tmp; + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) + tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; + tmp = [tmp componentsSeparatedByString:@":"]; +@@ -122,6 +131,10 @@ + return searchPathes; + } + +++ (NSString *)libraryDriversSubDir { ++ return [NSString stringWithFormat:@"SaxMappings"]; ++} ++ + + (id)modelWithName:(NSString *)_name { + NSFileManager *fileManager; + NSEnumerator *pathes; +Index: sope-xml/SaxObjC/GNUmakefile.preamble +=================================================================== +--- sope-xml/SaxObjC/GNUmakefile.preamble (révision 1632) ++++ sope-xml/SaxObjC/GNUmakefile.preamble (copie de travail) +@@ -1,9 +1,12 @@ + # compilation settings + ++include ./Version ++ + libSaxObjC_DLL_DEF = libSaxObjC.def +-libSaxObjC_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libSaxObjC_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libSaxObjC_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libSaxObjC_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) +-SaxObjC_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++SaxObjC_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) + SaxObjC_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libSaxObjC_HEADER_FILES_DIR = . +@@ -48,8 +51,8 @@ + ADDITIONAL_CPPFLAGS += -DFHS_INSTALL_ROOT=\@\"$(FHS_INSTALL_ROOT)\" + endif + +-ifeq ($(CONFIGURE_64BIT),yes) +-ADDITIONAL_CPPFLAGS += -DCONFIGURE_64BIT=1 ++ifneq ($(CGS_LIBDIR_NAME),) ++ADDITIONAL_CPPFLAGS += -DCGS_LIBDIR_NAME=\@\"$(CGS_LIBDIR_NAME)\" + endif + + # Apple +Index: sope-xml/SaxObjC/GNUmakefile +=================================================================== +--- sope-xml/SaxObjC/GNUmakefile (révision 1632) ++++ sope-xml/SaxObjC/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -56,10 +56,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/common.make +=================================================================== +--- sope-xml/common.make (révision 1632) ++++ sope-xml/common.make (copie de travail) +@@ -1,13 +1,7 @@ + # GNUstep makefile + +-SKYROOT=.. +- + include $(GNUSTEP_MAKEFILES)/common.make +-include $(SKYROOT)/Version +--include ./Version + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ADDITIONAL_CPPFLAGS += -pipe -Wall -Wno-protocol + + ADDITIONAL_INCLUDE_DIRS += -I.. +Index: sope-xml/samples/PlistSaxDriver/GNUmakefile +=================================================================== +--- sope-xml/samples/PlistSaxDriver/GNUmakefile (révision 1632) ++++ sope-xml/samples/PlistSaxDriver/GNUmakefile (copie de travail) +@@ -1,11 +1,11 @@ + # GNUstep Makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + BUNDLE_NAME = PlistSaxDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/Bundles ++BUNDLE_INSTALL_DIR = $(GNUSTEP_BUNDLES) + + PlistSaxDriver_OBJC_FILES = \ + PlistSaxDriver.m +Index: sope-xml/samples/GNUmakefile +=================================================================== +--- sope-xml/samples/GNUmakefile (révision 1632) ++++ sope-xml/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = \ +@@ -13,14 +13,20 @@ + testqp \ + + rss2plist1_OBJC_FILES = rss2plist1.m ++rss2plist1_INSTALL_DIR = $(SOPE_TOOLS)/ + rss2plist2_OBJC_FILES = rss2plist2.m ++rss2plist2_INSTALL_DIR = $(SOPE_TOOLS)/ + rssparse_OBJC_FILES = rssparse.m ++rssparse_INSTALL_DIR = $(SOPE_TOOLS)/ + saxxml_OBJC_FILES = saxxml.m ++saxxml_INSTALL_DIR = $(SOPE_TOOLS)/ + xmln_OBJC_FILES = xmln.m ++xmln_INSTALL_DIR = $(SOPE_TOOLS)/ + domxml_OBJC_FILES = domxml.m ++domxml_INSTALL_DIR = $(SOPE_TOOLS)/ + testqp_OBJC_FILES = testqp.m ++testqp_INSTALL_DIR = $(SOPE_TOOLS)/ + + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/samples/GNUmakefile.preamble +=================================================================== +--- sope-xml/samples/GNUmakefile.preamble (révision 1632) ++++ sope-xml/samples/GNUmakefile.preamble (copie de travail) +@@ -1,5 +1,6 @@ + # compilation settings + ++include ../../config.make + + rss2plist1_PCH_FILE = common.h + rss2plist2_PCH_FILE = common.h +@@ -42,8 +43,8 @@ + $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir)) + endif + +-ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64) +-SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64 ++ifneq ($(CGS_LIBDIR_NAME),) ++SYSTEM_LIB_DIR += -L/usr/local/$(CGS_LIBDIR_NAME) -L/usr/$(CGS_LIBDIR_NAME) + else + SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib + endif +Index: sope-xml/XmlRpc/GNUmakefile.preamble +=================================================================== +--- sope-xml/XmlRpc/GNUmakefile.preamble (révision 1632) ++++ sope-xml/XmlRpc/GNUmakefile.preamble (copie de travail) +@@ -1,10 +1,13 @@ + # compilation settings + ++include ./Version ++ + libXmlRpc_HEADER_FILES_DIR = . + libXmlRpc_HEADER_FILES_INSTALL_DIR = /XmlRpc +-libXmlRpc_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libXmlRpc_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libXmlRpc_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libXmlRpc_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) +-XmlRpc_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++XmlRpc_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) + XmlRpc_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + +Index: sope-xml/XmlRpc/GNUmakefile +=================================================================== +--- sope-xml/XmlRpc/GNUmakefile (révision 1632) ++++ sope-xml/XmlRpc/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + + ifneq ($(frameworks),yes) +@@ -43,10 +43,12 @@ + + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/STXSaxDriver/ExtraSTX/GNUmakefile +=================================================================== +--- sope-xml/STXSaxDriver/ExtraSTX/GNUmakefile (révision 1632) ++++ sope-xml/STXSaxDriver/ExtraSTX/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = ExtraSTX +Index: sope-xml/STXSaxDriver/GNUmakefile +=================================================================== +--- sope-xml/STXSaxDriver/GNUmakefile (révision 1632) ++++ sope-xml/STXSaxDriver/GNUmakefile (copie de travail) +@@ -1,13 +1,13 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version + + BUNDLE_NAME = STXSaxDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(SOPE_MAJOR_VERSION).$(SOPE_MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_SAXDRIVERS) + + STXSaxDriver_PCH_FILE = common.h + +@@ -24,4 +24,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/bundle.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-xml/STXSaxDriver/Model/GNUmakefile +=================================================================== +--- sope-xml/STXSaxDriver/Model/GNUmakefile (révision 1632) ++++ sope-xml/STXSaxDriver/Model/GNUmakefile (copie de travail) +@@ -6,7 +6,7 @@ + # Date: 24 November 2003 + # + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = Model +Index: sope-xml/pyxSAXDriver/GNUmakefile +=================================================================== +--- sope-xml/pyxSAXDriver/GNUmakefile (révision 1632) ++++ sope-xml/pyxSAXDriver/GNUmakefile (copie de travail) +@@ -1,17 +1,16 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version + + BUNDLE_NAME = pyxSAXDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/SaxDrivers-$(SOPE_MAJOR_VERSION).$(SOPE_MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = ${SOPE_SAXDRIVERS}/ + + pyxSAXDriver_OBJC_FILES = pyxSAXDriver.m + + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/bundle.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/GNUmakefile +=================================================================== +--- sope-appserver/GNUmakefile (révision 1632) ++++ sope-appserver/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-appserver +@@ -38,4 +38,4 @@ + # package + + macosx-pkg :: all +- ../maintenance/make-osxpkg.sh sope-appserver ++ ../maintenance/make-osxpkg.sh $(PACKAGE_NAME) +Index: sope-appserver/SoOFS/GNUmakefile.preamble +=================================================================== +--- sope-appserver/SoOFS/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/SoOFS/GNUmakefile.preamble (copie de travail) +@@ -76,17 +76,9 @@ + $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir)) + endif + +-ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64) +-SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64 +-else +-SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib +-endif +- +- +- + # platform specific settings + +-ifneq ($(findstring openbsd3, $(GNUSTEP_TARGET_OS)), openbsd3) ++ifneq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) + # OpenBSD does not require libcrypt + ifneq ($(findstring darwin, $(GNUSTEP_TARGET_OS)), darwin) + # and neither does MacOSX? ... +@@ -94,6 +86,6 @@ + endif + endif + +-ifeq ($(findstring openbsd3, $(GNUSTEP_TARGET_OS)), openbsd3) ++ifeq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) + $(SOPED_NAME)_TOOL_LIBS += -liconv + endif +Index: sope-appserver/SoOFS/GNUmakefile +=================================================================== +--- sope-appserver/SoOFS/GNUmakefile (révision 1632) ++++ sope-appserver/SoOFS/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -14,7 +14,8 @@ + + + libSoOFS_PCH_FILE = common.h +-libSoOFS_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libSoOFS_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libSoOFS_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libSoOFS_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libSoOFS_HEADER_FILES_DIR = . +@@ -75,7 +76,7 @@ + + BUNDLE_NAME = SoOFS + BUNDLE_EXTENSION = .sxp +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SoProducts-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_PRODUCTS)/ + + SoOFS_OBJC_FILES = SoOFSProduct.m + SoOFS_RESOURCE_FILES = product.plist Version +@@ -91,9 +92,13 @@ + TOOL_NAME = $(SOPED_NAME) + + $(SOPED_NAME)_OBJC_FILES = sope.m ++$(SOPED_NAME)_INSTALL_DIR = $(SOPE_ADMIN_TOOLS) + + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + include $(GNUSTEP_MAKEFILES)/bundle.make +@@ -102,4 +107,3 @@ + endif + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/NGXmlRpc/GNUmakefile +=================================================================== +--- sope-appserver/NGXmlRpc/GNUmakefile (révision 1632) ++++ sope-appserver/NGXmlRpc/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -12,7 +12,8 @@ + endif + + libNGXmlRpc_PCH_FILE = common.h +-libNGXmlRpc_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGXmlRpc_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGXmlRpc_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGXmlRpc_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGXmlRpc_HEADER_FILES_DIR = . +@@ -65,6 +66,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else +@@ -72,4 +76,3 @@ + endif + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/WEExtensions/GNUmakefile.preamble +=================================================================== +--- sope-appserver/WEExtensions/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/WEExtensions/GNUmakefile.preamble (copie de travail) +@@ -21,7 +21,8 @@ + cp ../bundle-info.plist .) + endif + +-libWEExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWEExtensions_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWEExtensions_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libWEExtensions_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + +Index: sope-appserver/WEExtensions/GNUmakefile +=================================================================== +--- sope-appserver/WEExtensions/GNUmakefile (révision 1632) ++++ sope-appserver/WEExtensions/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -11,7 +11,7 @@ + + BUNDLE_NAME = WEExtensions + BUNDLE_EXTENSION = .wox +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/WOxElemBuilders-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_WOXBUILDERS)/ + + else + FRAMEWORK_NAME = WEExtensions +@@ -99,6 +99,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + include $(GNUSTEP_MAKEFILES)/bundle.make +@@ -106,4 +109,3 @@ + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/WEExtensions/WEResourceManager.m +=================================================================== +--- sope-appserver/WEExtensions/WEResourceManager.m (révision 1632) ++++ sope-appserver/WEExtensions/WEResourceManager.m (copie de travail) +@@ -53,28 +53,43 @@ + + + (NSString *)gsTemplatesSubpath { + NSString *p; +- + p = [[WOApplication application] gsTemplatesDirectoryName]; ++#if ! GNUSTEP_BASE_LIBRARY ++ // for GNUSTEP_BASE_LIBRARY this is already there in rootPathesInGNUstep + p = [@"Library/" stringByAppendingString:p]; ++#endif + return p; + } + + (NSString *)gsWebSubpath { + NSString *p; + + p = [[WOApplication application] gsWebDirectoryName]; ++#if ! GNUSTEP_BASE_LIBRARY ++ // for GNUSTEP_BASE_LIBRARY this is already there in rootPathesInGNUstep + p = [@"Library/" stringByAppendingString:p]; ++#endif + return p; + } + + /* locate resource directories */ + + + (NSArray *)rootPathesInGNUstep { ++ id tmp; ++#if GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ ++ tmp = [[NSMutableArray alloc] init]; ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [tmp addObject: directory]; ++ return tmp; ++#else + NSDictionary *env; +- id tmp; +- + env = [[NSProcessInfo processInfo] environment]; + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) + tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; ++#endif + + return [tmp componentsSeparatedByString:@":"]; + } +@@ -95,9 +110,17 @@ + NSMutableArray *ma; + BOOL isDir; + id tmp; +- + fm = [NSFileManager defaultManager]; + ma = [NSMutableArray arrayWithCapacity:8]; ++ ++#ifdef GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent: _name]]; ++#else + + e = [[self rootPathesInGNUstep] objectEnumerator]; + while ((tmp = [e nextObject]) != nil) { +@@ -115,6 +138,7 @@ + + [ma addObject:tmp]; + } ++#endif + + /* hack in FHS pathes */ + +Index: sope-appserver/WEExtensions/WETableView/GNUmakefile +=================================================================== +--- sope-appserver/WEExtensions/WETableView/GNUmakefile (révision 1632) ++++ sope-appserver/WEExtensions/WETableView/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = WETableView +Index: sope-appserver/NGObjWeb/WOCoreApplication+Bundle.m +=================================================================== +--- sope-appserver/NGObjWeb/WOCoreApplication+Bundle.m (révision 1632) ++++ sope-appserver/NGObjWeb/WOCoreApplication+Bundle.m (copie de travail) +@@ -50,8 +50,6 @@ + } + else { + NSDictionary *env; +- NSEnumerator *e; +- id tmp; + + env = [[NSProcessInfo processInfo] environment]; + +@@ -67,7 +65,20 @@ + bp = @"/System/Library"; + bp = [bp stringByAppendingPathComponent:_domain]; + [chkPathes addObject:bp]; ++#elif GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) { ++ directory = [directory stringByAppendingPathComponent:_domain]; ++ if ([chkPathes containsObject:directory]) continue; ++ [chkPathes addObject:directory]; ++ ++ } + #else ++ NSEnumerator *e; ++ id tmp; + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) + tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; + tmp = [tmp componentsSeparatedByString:@":"]; +Index: sope-appserver/NGObjWeb/wobundle-gs.make +=================================================================== +--- sope-appserver/NGObjWeb/wobundle-gs.make (révision 1632) ++++ sope-appserver/NGObjWeb/wobundle-gs.make (copie de travail) +@@ -85,7 +85,7 @@ + endif + + ifeq ($(WOBUNDLE_INSTALL_DIR),) +-WOBUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Libraries ++WOBUNDLE_INSTALL_DIR = $(GNUSTEP_WEB_APPS) + endif + # The name of the bundle is in the BUNDLE_NAME variable. + # The list of languages the bundle is localized in are in xxx_LANGUAGES +@@ -287,8 +287,10 @@ + @$(MKDIRS) $@ + + internal-wobundle-install_:: $(WOBUNDLE_INSTALL_DIR) shared-instance-headers-install +- rm -rf $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME); \ +- $(TAR) chf - --exclude=CVS --exclude=.svn --to-stdout $(WOBUNDLE_DIR_NAME) | (cd $(WOBUNDLE_INSTALL_DIR); $(TAR) xf -) ++# rm -rf $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME); \ ++# $(TAR) chf - --exclude=CVS --exclude=.svn --to-stdout $(WOBUNDLE_DIR_NAME) | (cd $(WOBUNDLE_INSTALL_DIR); $(TAR) xf -) ++ if [ -e $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME) ]; then rm -rf $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME); fi; \ ++ cp -LR $(WOBUNDLE_DIR_NAME) $(WOBUNDLE_INSTALL_DIR) + ifneq ($(CHOWN_TO),) + $(CHOWN) -R $(CHOWN_TO) $(WOBUNDLE_INSTALL_DIR)/$(WOBUNDLE_DIR_NAME) + endif +Index: sope-appserver/NGObjWeb/GNUmakefile.preamble +=================================================================== +--- sope-appserver/NGObjWeb/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/NGObjWeb/GNUmakefile.preamble (copie de travail) +@@ -50,9 +50,6 @@ + $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir)) + endif + +-SYSTEM_LIB_DIR += $(CONFIGURE_SYSTEM_LIB_DIR) +- +- + # dependencies + + ifneq ($(frameworks),yes) +@@ -85,6 +82,7 @@ + $(sope-mime-libs) \ + $(sope-core-libs) \ + $(sope-xml-libs) ++wod_INSTALL_DIR = $(SOPE_TOOLS) + SoCore_BUNDLE_LIBS += \ + $(sope-ngobjweb-libs) \ + $(sope-mime-libs) \ +@@ -94,7 +92,7 @@ + + # platform specific settings + +-ifneq ($(findstring openbsd3, $(GNUSTEP_TARGET_OS)), openbsd3) ++ifneq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) + # OpenBSD does not require libcrypt + ifneq ($(findstring darwin, $(GNUSTEP_TARGET_OS)), darwin) + # and neither does MacOSX? ... +@@ -116,6 +114,6 @@ + libNGObjWeb_LIBRARIES_DEPEND_UPON += -lFoundationExt + endif + +-ifeq ($(findstring openbsd3, $(GNUSTEP_TARGET_OS)), openbsd3) ++ifeq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) + wod_TOOL_LIBS += -liconv + endif +Index: sope-appserver/NGObjWeb/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/GNUmakefile (copie de travail) +@@ -1,11 +1,9 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + include ./Version + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ifneq ($(frameworks),yes) + LIBRARY_NAME = libNGObjWeb + else +@@ -14,15 +12,12 @@ + + + ifneq ($(frameworks),yes) +-ifeq ($(FHS_INSTALL_ROOT),) +-RESOURCES_DIR = $(GNUSTEP_RESOURCES)/NGObjWeb +-else +-RESOURCES_DIR = $(FHS_INSTALL_ROOT)/share/sope-$(MAJOR_VERSION).$(MINOR_VERSION)/ngobjweb ++RESOURCES_DIR = $(SOPE_NGOBJWEB)/ + endif +-endif + + libNGObjWeb_PCH_FILE = common.h +-libNGObjWeb_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGObjWeb_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGObjWeb_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGObjWeb_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGObjWeb_SUBPROJECTS = \ +@@ -40,7 +35,7 @@ + libNGObjWeb_RESOURCES = \ + Defaults.plist \ + Languages.plist \ +- DAVPropMap.plist \ ++ DAVPropMap.plist + + FHS_MANPAGES += \ + sope-ngobjweb-defaults.5 \ +@@ -167,7 +162,7 @@ + + BUNDLE_NAME = SoCore + BUNDLE_EXTENSION = .sxp +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SoProducts-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_PRODUCTS)/ + + SoCore_PCH_FILE = common.h + SoCore_OBJC_FILES = SoCoreProduct.m +@@ -190,6 +185,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else +@@ -198,4 +196,3 @@ + include $(GNUSTEP_MAKEFILES)/bundle.make + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/NGObjWeb/WebDAV/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/WebDAV/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/WebDAV/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include ../../Version + include ../Version + include $(GNUSTEP_MAKEFILES)/common.make +Index: sope-appserver/NGObjWeb/DynamicElements/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/DynamicElements/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/DynamicElements/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = DynamicElements +Index: sope-appserver/NGObjWeb/SoObjects/SoProductLoader.m +=================================================================== +--- sope-appserver/NGObjWeb/SoObjects/SoProductLoader.m (révision 1632) ++++ sope-appserver/NGObjWeb/SoObjects/SoProductLoader.m (copie de travail) +@@ -74,6 +74,14 @@ + } + + - (void)_addGNUstepSearchPathesToArray:(NSMutableArray *)ma { ++#if GNUSTEP_BASE_LIBRARY ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ while ((directory = [libraryPaths nextObject])) ++ [ma addObject: [directory stringByAppendingPathComponent: self->productDirectoryName]]; ++#else + NSDictionary *env; + id tmp; + +@@ -97,6 +105,7 @@ + [self logWithFormat:@"%s: empty library search path !", + __PRETTY_FUNCTION__]; + } ++#endif + } + + - (void)_addFHSPathesToArray:(NSMutableArray *)ma { +Index: sope-appserver/NGObjWeb/SoObjects/SoProductRegistry.m +=================================================================== +--- sope-appserver/NGObjWeb/SoObjects/SoProductRegistry.m (révision 1632) ++++ sope-appserver/NGObjWeb/SoObjects/SoProductRegistry.m (copie de travail) +@@ -231,7 +231,7 @@ + + fm = [NSFileManager defaultManager]; + pi = [NSProcessInfo processInfo]; +- ++#if ! GNUSTEP_BASE_LIBRARY + #if COCOA_Foundation_LIBRARY && !COMPILE_FOR_GNUSTEP + /* + TODO: (like COMPILE_FOR_GNUSTEP) +@@ -250,12 +250,9 @@ + pathes = [[pathes stringValue] componentsSeparatedByString:@":"]; + relPath = @"Library/"; + #endif +- +- [self debugWithFormat:@"scanning for products ..."]; +- + relPath = [relPath stringByAppendingFormat:@"SoProducts-%i.%i/", + SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION]; +- ++ [self debugWithFormat:@"scanning for products ..."]; + for (i = 0; i < [pathes count]; i++) { + NSString *lPath; + BOOL isDir; +@@ -271,7 +268,38 @@ + [self debugWithFormat:@" directory %@", lPath]; + [self scanForProductsInDirectory:lPath]; + } ++#else ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ NSMutableArray *tmppath; + ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ tmppath = [[NSMutableArray alloc] init]; ++ while ((directory = [libraryPaths nextObject])) ++ [tmppath addObject: [directory stringByAppendingPathComponent: ++ [NSString stringWithFormat:@"SoProducts-%i.%i/", ++ SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION]]]; ++ pathes = [tmppath mutableCopy]; ++ [self debugWithFormat:@"scanning for products ..."]; ++ for (i = 0; i < [pathes count]; i++) { ++ NSString *lPath; ++ BOOL isDir; ++ ++ lPath = [pathes objectAtIndex:i]; ++ [self debugWithFormat:@" scan: %@", lPath]; ++ ++ if (![fm fileExistsAtPath:lPath isDirectory:&isDir]) ++ continue; ++ if (!isDir) ++ continue; ++ ++ [self debugWithFormat:@" directory %@", lPath]; ++ [self scanForProductsInDirectory:lPath]; ++ } ++ [tmppath release]; ++#endif ++ ++ + #if COCOA_Foundation_LIBRARY + /* look in wrapper places */ + bundle = [NSBundle bundleForClass:[self class]]; +@@ -282,8 +310,8 @@ + /* look into FHS pathes */ + + relPath = [NSString stringWithFormat: +-#if CONFIGURE_64BIT +- @"lib64/sope-%i.%i/products/", ++#ifdef CGS_LIBDIR_NAME ++ [CGS_LIBDIR_NAME stringByAppendingString:@"/sope-%i.%i/products/"], + #else + @"lib/sope-%i.%i/products/", + #endif +Index: sope-appserver/NGObjWeb/SoObjects/GNUmakefile.preamble +=================================================================== +--- sope-appserver/NGObjWeb/SoObjects/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/NGObjWeb/SoObjects/GNUmakefile.preamble (copie de travail) +@@ -1,5 +1,7 @@ + # compilation settings + ++include ../../../config.make ++ + ADDITIONAL_INCLUDE_DIRS += -I../WebDAV/ + + ADDITIONAL_CPPFLAGS += -DCOMPILING_NGOBJWEB=1 -DCOMPILE_FOR_GNUSTEP=1 +@@ -10,6 +12,6 @@ + ADDITIONAL_CPPFLAGS += -DFHS_INSTALL_ROOT=\@\"$(FHS_INSTALL_ROOT)\" + endif + +-ifeq ($(CONFIGURE_64BIT),yes) +-ADDITIONAL_CPPFLAGS += -DCONFIGURE_64BIT=1 ++ifneq ($(CGS_LIBDIR_NAME),) ++ADDITIONAL_CPPFLAGS += -DCGS_LIBDIR_NAME=\@\"$(CGS_LIBDIR_NAME)\" + endif +Index: sope-appserver/NGObjWeb/SoObjects/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/SoObjects/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/SoObjects/GNUmakefile (copie de travail) +@@ -1,7 +1,7 @@ + # GNUstep makefile + +--include ../../../config.make + include ../subdirs.make ++include ../../../config.make + + SUBPROJECT_NAME = SoObjects + +Index: sope-appserver/NGObjWeb/Templates/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/Templates/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/Templates/GNUmakefile (copie de travail) +@@ -1,7 +1,7 @@ + # GNUmakefile makefile + +--include ../../../config.make + include ../subdirs.make ++include ../../../config.make + + SUBPROJECT_NAME = Templates + +Index: sope-appserver/NGObjWeb/Templates/WOApplication+Builders.m +=================================================================== +--- sope-appserver/NGObjWeb/Templates/WOApplication+Builders.m (révision 1632) ++++ sope-appserver/NGObjWeb/Templates/WOApplication+Builders.m (copie de travail) +@@ -76,7 +76,7 @@ + + fm = [NSFileManager defaultManager]; + pi = [NSProcessInfo processInfo]; +- ++#if ! GNUSTEP_BASE_LIBRARY + #if COCOA_Foundation_LIBRARY + /* + TODO: (like COMPILE_FOR_GNUSTEP) +@@ -121,16 +121,43 @@ + [self debugWithFormat:@" directory %@", lPath]; + [self scanForBuilderBundlesInDirectory:lPath]; + } ++#else ++ NSEnumerator *libraryPaths; ++ NSString *directory; ++ NSMutableArray *tmppathes; ++ ++ libraryPaths = [NSStandardLibraryPaths() objectEnumerator]; ++ tmppathes = [[NSMutableArray alloc] init]; ++ while ((directory = [libraryPaths nextObject])) ++ [tmppathes addObject: [directory stringByAppendingPathComponent: ++ [NSString stringWithFormat:@"WOxElemBuilders-%i.%i/", ++ SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION]]]; ++ pathes = [tmppathes mutableCopy]; ++ for (i = 0; i < [pathes count]; i++) { ++ NSString *lPath; ++ BOOL isDir; ++ ++ lPath = [pathes objectAtIndex:i]; ++ if (![fm fileExistsAtPath:lPath isDirectory:&isDir]) ++ continue; ++ if (!isDir) ++ continue; ++ ++ [self debugWithFormat:@" directory %@", lPath]; ++ [self scanForBuilderBundlesInDirectory:lPath]; ++ } ++ [tmppathes release]; ++#endif + + /* look into FHS pathes */ + + relPath = [NSString stringWithFormat: +-#if CONFIGURE_64BIT +- @"lib/sope-%i.%i/wox-builders/", ++#ifdef CGS_LIBDIR_NAME ++ [CGS_LIBDIR_NAME stringByAppendingString:@"/sope-%i.%i/wox-builders/"], + #else +- @"lib64/sope-%i.%i/wox-builders/", ++ @"lib/sope-%i.%i/wox-builders/", + #endif +- SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION]; ++ SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION]; + pathes = [NSArray arrayWithObjects: + #ifdef FHS_INSTALL_ROOT + [FHS_INSTALL_ROOT stringByAppendingString:relPath], +Index: sope-appserver/NGObjWeb/Templates/GNUmakefile.preamble +=================================================================== +--- sope-appserver/NGObjWeb/Templates/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/NGObjWeb/Templates/GNUmakefile.preamble (copie de travail) +@@ -6,6 +6,6 @@ + ADDITIONAL_CPPFLAGS += -DFHS_INSTALL_ROOT=\@\"$(FHS_INSTALL_ROOT)\" + endif + +-ifeq ($(CONFIGURE_64BIT),yes) +-ADDITIONAL_CPPFLAGS += -DCONFIGURE_64BIT=1 ++ifneq ($(CGS_LIBDIR_NAME),) ++ADDITIONAL_CPPFLAGS += -DCGS_LIBDIR_NAME=\@\"$(CGS_LIBDIR_NAME)\" + endif +Index: sope-appserver/NGObjWeb/Associations/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/Associations/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/Associations/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = Associations +Index: sope-appserver/NGObjWeb/WOHttpAdaptor/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/WOHttpAdaptor/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/WOHttpAdaptor/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = WOHttpAdaptor +Index: sope-appserver/NGObjWeb/woapp-gs.make +=================================================================== +--- sope-appserver/NGObjWeb/woapp-gs.make (révision 1632) ++++ sope-appserver/NGObjWeb/woapp-gs.make (copie de travail) +@@ -103,7 +103,7 @@ + # Determine the application directory extension + WOAPP_EXTENSION = woa + +-GNUSTEP_WOAPPS = $(GNUSTEP_INSTALLATION_DIR)/WOApps ++GNUSTEP_WOAPPS = $(GNUSTEP_WEB_APPS) + + .PHONY: internal-woapp-all_ \ + internal-woapp-install_ \ +@@ -372,8 +372,9 @@ + + internal-woapp-install_:: + @($(MKINSTALLDIRS) $(GNUSTEP_WOAPPS); \ +- rm -rf $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME); \ +- $(TAR) chf - --exclude=CVS --exclude=.svn --to-stdout $(WOAPP_DIR_NAME) | (cd $(GNUSTEP_WOAPPS); $(TAR) xf -)) ++ if [ -e $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME) ]; then rm -rf $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME); fi; \ ++# $(TAR) chf - --exclude=CVS --exclude=.svn --to-stdout $(WOAPP_DIR_NAME) | (cd $(GNUSTEP_WOAPPS); $(TAR) xf -)) ++ cp -LR $(WOAPP_DIR_NAME) $(GNUSTEP_WOAPPS) + ifneq ($(CHOWN_TO),) + $(CHOWN) -R $(CHOWN_TO) $(GNUSTEP_WOAPPS)/$(WOAPP_DIR_NAME) + endif +Index: sope-appserver/NGObjWeb/WOCoreApplication.m +=================================================================== +--- sope-appserver/NGObjWeb/WOCoreApplication.m (révision 1632) ++++ sope-appserver/NGObjWeb/WOCoreApplication.m (copie de travail) +@@ -730,9 +730,15 @@ + [self sopeMajorVersion], [self sopeMinorVersion]]; + } + + (NGResourceLocator *)ngobjwebResourceLocator { ++#if GNUSTEP_BASE_LIBRARY + return [NGResourceLocator resourceLocatorForGNUstepPath: ++ @"Libraries/Resources/NGObjWeb" ++ fhsPath:[self ngobjwebShareDirectorySubPath]]; ++#else ++ return [NGResourceLocator resourceLocatorForGNUstepPath: + @"Library/Libraries/Resources/NGObjWeb" + fhsPath:[self ngobjwebShareDirectorySubPath]]; ++#endif + } + + + (NSArray *)resourcesSearchPathes { +Index: sope-appserver/NGObjWeb/NGHttp/GNUmakefile +=================================================================== +--- sope-appserver/NGObjWeb/NGHttp/GNUmakefile (révision 1632) ++++ sope-appserver/NGObjWeb/NGHttp/GNUmakefile (copie de travail) +@@ -1,10 +1,8 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + SUBPROJECT_NAME = NGHttp + + NGHttp_PCH_FILE = common.h +@@ -37,5 +35,8 @@ + NGUrlFormCoder.m \ + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + include $(GNUSTEP_MAKEFILES)/subproject.make + -include GNUmakefile.postamble +Index: sope-appserver/WEPrototype/GNUmakefile +=================================================================== +--- sope-appserver/WEPrototype/GNUmakefile (révision 1632) ++++ sope-appserver/WEPrototype/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -10,7 +10,7 @@ + + BUNDLE_NAME = WEPrototype + BUNDLE_EXTENSION = .wox +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/WOxElemBuilders-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_WOXBUILDERS)/ + else + FRAMEWORK_NAME = WEPrototype + endif +@@ -46,6 +46,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + include $(GNUSTEP_MAKEFILES)/bundle.make +@@ -53,4 +56,3 @@ + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/WEPrototype/doc/GNUmakefile +=================================================================== +--- sope-appserver/WEPrototype/doc/GNUmakefile (révision 1632) ++++ sope-appserver/WEPrototype/doc/GNUmakefile (copie de travail) +@@ -2,7 +2,7 @@ + + SOPE_ROOT=../../.. + +--include $(SOPE_ROOT)/config.make ++include $(SOPE_ROOT)/config.make + include $(SOPE_ROOT)/Version + include ../Version + +Index: sope-appserver/WEPrototype/GNUmakefile.preamble +=================================================================== +--- sope-appserver/WEPrototype/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/WEPrototype/GNUmakefile.preamble (copie de travail) +@@ -1,4 +1,4 @@ +-# compiler flags ++# GNUstep makefile + + SOPE_ROOT=../.. + +@@ -21,7 +21,8 @@ + -I$(SOPE_ROOT)/sope-xml + + +-libWEPrototype_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWEPrototype_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWEPrototype_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libWEPrototype_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libWEPrototype_LIBRARIES_DEPEND_UPON += \ +Index: sope-appserver/common.make +=================================================================== +--- sope-appserver/common.make (révision 1632) ++++ sope-appserver/common.make (copie de travail) +@@ -4,8 +4,6 @@ + include ../Version + -include ./Version + +-GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_LOCAL_ROOT) +- + ADDITIONAL_CPPFLAGS += -pipe -Wall -Wno-protocol + + ADDITIONAL_INCLUDE_DIRS += \ +Index: sope-appserver/samples/CoreDataBlog/GNUmakefile +=================================================================== +--- sope-appserver/samples/CoreDataBlog/GNUmakefile (révision 1632) ++++ sope-appserver/samples/CoreDataBlog/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = CoreDataBlog +Index: sope-appserver/samples/HelloForm/GNUmakefile +=================================================================== +--- sope-appserver/samples/HelloForm/GNUmakefile (révision 1632) ++++ sope-appserver/samples/HelloForm/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = HelloForm +Index: sope-appserver/samples/GNUmakefile +=================================================================== +--- sope-appserver/samples/GNUmakefile (révision 1632) ++++ sope-appserver/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECTS += \ +Index: sope-appserver/samples/iCalPortal/GNUmakefile.preamble +=================================================================== +--- sope-appserver/samples/iCalPortal/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/samples/iCalPortal/GNUmakefile.preamble (copie de travail) +@@ -7,7 +7,9 @@ + -lEOControl \ + -lXmlRpc -lDOM -lSaxObjC + else ++ifneq ($(findstring openbsd, $(GNUSTEP_TARGET_OS)), openbsd) + ADDITIONAL_TOOL_LIBS += -lcrypt + endif ++endif + + SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib +Index: sope-appserver/samples/iCalPortal/GNUmakefile +=================================================================== +--- sope-appserver/samples/iCalPortal/GNUmakefile (révision 1632) ++++ sope-appserver/samples/iCalPortal/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = iCalPortal +Index: sope-appserver/samples/iCalPortal/Pages/GNUmakefile +=================================================================== +--- sope-appserver/samples/iCalPortal/Pages/GNUmakefile (révision 1632) ++++ sope-appserver/samples/iCalPortal/Pages/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../../config.make ++include ../../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = Pages +Index: sope-appserver/samples/iCalPortal/WebDAV/GNUmakefile +=================================================================== +--- sope-appserver/samples/iCalPortal/WebDAV/GNUmakefile (révision 1632) ++++ sope-appserver/samples/iCalPortal/WebDAV/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../../config.make ++include ../../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + SUBPROJECT_NAME = DAV +Index: sope-appserver/samples/SoCookieAuth/GNUmakefile +=================================================================== +--- sope-appserver/samples/SoCookieAuth/GNUmakefile (révision 1632) ++++ sope-appserver/samples/SoCookieAuth/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = SoCookieAuth +Index: sope-appserver/samples/WOxExtTest/GNUmakefile +=================================================================== +--- sope-appserver/samples/WOxExtTest/GNUmakefile (révision 1632) ++++ sope-appserver/samples/WOxExtTest/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = WOxExtTest +Index: sope-appserver/samples/TestPages/GNUmakefile +=================================================================== +--- sope-appserver/samples/TestPages/GNUmakefile (révision 1632) ++++ sope-appserver/samples/TestPages/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = TestPages +Index: sope-appserver/samples/parsedav/GNUmakefile +=================================================================== +--- sope-appserver/samples/parsedav/GNUmakefile (révision 1632) ++++ sope-appserver/samples/parsedav/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = parsedav +Index: sope-appserver/samples/xmlrpc/GNUmakefile +=================================================================== +--- sope-appserver/samples/xmlrpc/GNUmakefile (révision 1632) ++++ sope-appserver/samples/xmlrpc/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = \ +Index: sope-appserver/samples/TestPrototype/GNUmakefile +=================================================================== +--- sope-appserver/samples/TestPrototype/GNUmakefile (révision 1632) ++++ sope-appserver/samples/TestPrototype/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = TestPrototype +Index: sope-appserver/samples/HelloWorld/GNUmakefile +=================================================================== +--- sope-appserver/samples/HelloWorld/GNUmakefile (révision 1632) ++++ sope-appserver/samples/HelloWorld/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + WOAPP_NAME = HelloWorld +Index: sope-appserver/samples/davpropget/GNUmakefile +=================================================================== +--- sope-appserver/samples/davpropget/GNUmakefile (révision 1632) ++++ sope-appserver/samples/davpropget/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../../config.make ++include ../../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = davpropget +Index: sope-appserver/WOExtensions/GNUmakefile.preamble +=================================================================== +--- sope-appserver/WOExtensions/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/WOExtensions/GNUmakefile.preamble (copie de travail) +@@ -12,7 +12,8 @@ + -I$(SOPE_ROOT)/sope-xml + + +-libWOExtensions_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWOExtensions_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWOExtensions_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libWOExtensions_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + +Index: sope-appserver/WOExtensions/GNUmakefile +=================================================================== +--- sope-appserver/WOExtensions/GNUmakefile (révision 1632) ++++ sope-appserver/WOExtensions/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ../Version + include ./Version +@@ -9,7 +9,7 @@ + LIBRARY_NAME = libWOExtensions + BUNDLE_NAME = WOExtensions + BUNDLE_EXTENSION = .wox +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/WOxElemBuilders-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_WOXBUILDERS)/ + + else + FRAMEWORK_NAME = WOExtensions +@@ -71,6 +71,9 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + include $(GNUSTEP_MAKEFILES)/bundle.make +@@ -78,4 +81,3 @@ + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/WOXML/GNUmakefile +=================================================================== +--- sope-appserver/WOXML/GNUmakefile (révision 1632) ++++ sope-appserver/WOXML/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include ../common.make + include ../Version + include ./Version +@@ -15,6 +15,7 @@ + libWOXML_PCH_FILE = common.h + libWOXML_HEADER_FILES_DIR = . + libWOXML_HEADER_FILES_INSTALL_DIR = /WOXML ++libWOXML_INSTALL_DIR=$(SOPE_SYSLIBDIR) + + + libWOXML_HEADER_FILES += \ +@@ -42,10 +43,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make +Index: sope-appserver/WOXML/GNUmakefile.preamble +=================================================================== +--- sope-appserver/WOXML/GNUmakefile.preamble (révision 1632) ++++ sope-appserver/WOXML/GNUmakefile.preamble (copie de travail) +@@ -2,7 +2,7 @@ + + SOPE_ROOT=../.. + +-libWOXML_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libWOXML_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) + libWOXML_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libWOXML_INCLUDE_DIRS += -I. -I.. +Index: sope-ical/samples/GNUmakefile +=================================================================== +--- sope-ical/samples/GNUmakefile (révision 1632) ++++ sope-ical/samples/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + TOOL_NAME = icalparsetest icalds vcf2xml vcfparsetest ievalrrule +@@ -14,4 +14,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/tool.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-ical/versitSaxDriver/GNUmakefile +=================================================================== +--- sope-ical/versitSaxDriver/GNUmakefile (révision 1632) ++++ sope-ical/versitSaxDriver/GNUmakefile (copie de travail) +@@ -1,13 +1,13 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + -include ../../Version + -include ./Version + + BUNDLE_NAME = versitSaxDriver + BUNDLE_EXTENSION = .sax +-BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/ ++BUNDLE_INSTALL_DIR = $(SOPE_SAXDRIVERS)/ + + versitSaxDriver_PRINCIPAL_CLASS = VSSaxDriver + +@@ -24,4 +24,3 @@ + -include GNUmakefile.preamble + include $(GNUSTEP_MAKEFILES)/bundle.make + -include GNUmakefile.postamble +--include fhs.make +Index: sope-ical/GNUmakefile +=================================================================== +--- sope-ical/GNUmakefile (révision 1632) ++++ sope-ical/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../config.make ++include ../config.make + include $(GNUSTEP_MAKEFILES)/common.make + + PACKAGE_NAME=sope-ical +Index: sope-ical/NGiCal/GNUmakefile.postamble +=================================================================== +--- sope-ical/NGiCal/GNUmakefile.postamble (révision 1632) ++++ sope-ical/NGiCal/GNUmakefile.postamble (copie de travail) +@@ -1,10 +1,6 @@ + # compilation settings + +-ifeq ($(FHS_INSTALL_ROOT),) +-MAPDIR="$(GNUSTEP_INSTALLATION_DIR)/Library/SaxMappings/" +-else +-MAPDIR="$(FHS_INSTALL_ROOT)/share/sope-$(MAJOR_VERSION).$(MINOR_VERSION)/saxmappings/" +-endif ++MAPDIR="$(SOPE_SAXMAPPINGS)/" + + mappings-dir :: + $(MKDIRS) $(MAPDIR) +Index: sope-ical/NGiCal/GNUmakefile +=================================================================== +--- sope-ical/NGiCal/GNUmakefile (révision 1632) ++++ sope-ical/NGiCal/GNUmakefile (copie de travail) +@@ -1,6 +1,6 @@ + # GNUstep makefile + +--include ../../config.make ++include ../../config.make + include $(GNUSTEP_MAKEFILES)/common.make + include ./Version + +@@ -14,7 +14,8 @@ + libNGiCal_PCH_FILE = common.h + libNGiCal_HEADER_FILES_DIR = . + libNGiCal_HEADER_FILES_INSTALL_DIR = /NGiCal +-libNGiCal_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGiCal_INTERFACE_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) ++libNGiCal_INSTALL_DIR=$(SOPE_SYSLIBDIR) + libNGiCal_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION) + + libNGiCal_HEADER_FILES = \ +@@ -107,10 +108,12 @@ + # building + + -include GNUmakefile.preamble ++ifneq ($(FHS_INSTALL_ROOT),) ++GNUSTEP_HEADERS=$(DESTDIR)$(FHS_INSTALL_ROOT)/include ++endif + ifneq ($(frameworks),yes) + include $(GNUSTEP_MAKEFILES)/library.make + else + include $(GNUSTEP_MAKEFILES)/framework.make + endif + -include GNUmakefile.postamble +--include fhs.make --- sope-4.9.r1664.orig/debian/patches/debian-build-mysql.diff +++ sope-4.9.r1664/debian/patches/debian-build-mysql.diff @@ -0,0 +1,13 @@ +diff -durpN sope-4.9.r1660.orig/configure sope-4.9.r1660/configure +--- configure.orig 2009-10-28 09:46:53.000000000 -0400 ++++ configure 2009-10-28 09:48:41.000000000 -0400 +@@ -475,8 +475,8 @@ checkDependencies() { + checkLinking "ssl" required; # TODO: make optional + fi + checkLinking "pq" optional; +- checkLinking "sqlite3" optional; + checkLinking "mysqlclient" optional; ++ checkLinking "sqlite3" optional; + } + + runIt() {