]> granicus.if.org Git - php/commitdiff
moved apache, com and hyperwave into ext/
authorStig Bakken <ssb@php.net>
Wed, 21 Apr 1999 23:11:20 +0000 (23:11 +0000)
committerStig Bakken <ssb@php.net>
Wed, 21 Apr 1999 23:11:20 +0000 (23:11 +0000)
21 files changed:
Makefile.in
acconfig.h.in
configure.in.in
ext/apache/Makefile.am [new file with mode: 0644]
ext/apache/apache.c [new file with mode: 0644]
ext/apache/config.m4 [new file with mode: 0644]
ext/com/php3_COM.h [new file with mode: 0644]
ext/hyperwave/DList.h [new file with mode: 0644]
ext/hyperwave/Makefile.am [new file with mode: 0644]
ext/hyperwave/config.h.stub [new file with mode: 0644]
ext/hyperwave/config.m4 [new file with mode: 0644]
ext/hyperwave/dlist.c [new file with mode: 0644]
ext/hyperwave/hg_comm.c [new file with mode: 0644]
ext/hyperwave/hg_comm.h [new file with mode: 0644]
ext/hyperwave/hw.c [new file with mode: 0644]
ext/hyperwave/hw.h [new file with mode: 0644]
ext/hyperwave/hw_error.h [new file with mode: 0644]
ext/hyperwave/setup.stub [new file with mode: 0644]
ext/rpc/com/COM.c [new file with mode: 0644]
ext/rpc/com/php3_COM.h [new file with mode: 0644]
setup

index 8542f082fc22c5f5d145a99d200ae3cad13f4a74..60bb0e40461e6217f35cb41bb59b8de98843c8c2 100644 (file)
@@ -68,18 +68,18 @@ OBJS = main.o internal_functions.o snprintf.o php3_sprintf.o \
        safe_mode.o fopen-wrappers.o php3_realpath.o alloca.o output.o \
        php_ini.o
 
-FUNCTIONS_SOURCE = functions/apache.c functions/fhttpd.c \
+FUNCTIONS_SOURCE = functions/fhttpd.c \
        functions/crypt.c functions/db.c functions/dl.c \
        functions/head.c functions/imap.c functions/mime.c \
        functions/pgsql.c functions/post.c functions/sybase.c \
        functions/sybase-ct.c @BCMATH_SRC@ functions/xml.c \
-       functions/ldap.c functions/zlib.c functions/COM.c functions/ifx.c \
-       functions/pdf.c functions/hw.c functions/hg_comm.c functions/dlist.c \
+       functions/ldap.c functions/zlib.c functions/ifx.c \
+       functions/pdf.c \
        functions/fdf.c functions/snmp.c functions/interbase.c \
        functions/sysvsem.c functions/sysvshm.c
 
 FUNCTIONS = $(FUNCTIONS_SOURCE:.c=.o)
-PHPLIBS = -L@top_srcdir@/libzend -lzend -Lext -lphpext
+PHPLIBS = -L@top_srcdir@/libzend -lzend -L@top_srcdir@/ext -lphpext
 LIBS = $(PHPLIBS) $(EXTRA_LIBS) @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @FHTTPD_LIB@ @REGEX_LIB@ @DBM_LIB@ @SYBASE_LFLAGS@ @SYBASE_LIBS@ @SYBASE_CT_LFLAGS@ @SYBASE_CT_LIBS@ @MYSQL_LFLAGS@ @MYSQL_LIBS@ @PGSQL_LFLAGS@ @PGSQL_LIBS@ @LDAP_LFLAGS@ @LDAP_LIBS@ @IMAP_LIBS@ @ZLIB_LIBS@ @PDFLIB_LIBS@ @FDFLIB_LIBS@ @IFX_LFLAGS@ @IFX_LIBS@ @SNMP_LFLAGS@ @SNMP_LIBS@ @IBASE_LFLAGS@ @IBASE_LIBS@ @XML_LIBS@ @LIBS@
 
 all: $(BINNAME)
index f1ece7cefb7481520024ade580770af659d0810b..5799877b47c5c6bc8cbfd081f03f7920198d0c73 100644 (file)
@@ -64,9 +64,6 @@
 #define REGEX 0
 #define HSREGEX 0
 
-/* Define if you want Hyperwave support */
-#define HYPERWAVE 0
-
 /* Define if you have the crypt() function */
 #define HAVE_CRYPT 1
 
index b226b6bdf7c3bf940cf2e36deb8fd42a5c56b654..a47ef5cf58b09044d91a33fbd76a7c2bb4972c05 100644 (file)
@@ -1152,23 +1152,6 @@ dnl## AC_SUBST(IBASE_INCLUDE)
 INCLUDES="$INCLUDES $IBASE_INCLUDE"
 
 
-AC_MSG_CHECKING(for Hyperwave support)
-AC_ARG_WITH(hyperwave,
-[  --with-hyperwave        Include Hyperwave support],
-[
-  if test "$withval" != "no"; then
-    AC_DEFINE(HYPERWAVE,1)
-    AC_MSG_RESULT(yes)
-  else
-    AC_DEFINE(HYPERWAVE,0)
-    AC_MSG_RESULT(no)
-  fi
-],[
-  AC_DEFINE(HYPERWAVE,0)
-  AC_MSG_RESULT(no)
-])
-
-
 AC_MSG_CHECKING(for XML support)
 AC_ARG_WITH(xml,
 [  --with-xml              Include XML support],[
diff --git a/ext/apache/Makefile.am b/ext/apache/Makefile.am
new file mode 100644 (file)
index 0000000..c9006e1
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id$
+
+INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend
+noinst_LIBRARIES=libphpext_apache.a
+libphpext_apache_a_SOURCES=apache.c
+
diff --git a/ext/apache/apache.c b/ext/apache/apache.c
new file mode 100644 (file)
index 0000000..614268d
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of one of the following licenses:                 |
+   |                                                                      |
+   |  A) the GNU General Public License as published by the Free Software |
+   |     Foundation; either version 2 of the License, or (at your option) |
+   |     any later version.                                               |
+   |                                                                      |
+   |  B) the PHP License as published by the PHP Development Team and     |
+   |     included in the distribution in the file: LICENSE                |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of both licenses referred to here.   |
+   | If you did not, or have any questions about PHP licensing, please    |
+   | contact core@php.net.                                                |
+   +----------------------------------------------------------------------+
+   | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
+   |          Stig Sæther Bakken <ssb@guardian.no>                        |
+   |          David Sklar <sklar@student.net>                             |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+#ifdef THREAD_SAFE
+#include "tls.h"
+#endif
+#include "php.h"
+#include "functions/head.h"
+#include "php_globals.h"
+#include "php_ini.h"
+#include "mod_php3.h"
+
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#if APACHE
+#include "http_request.h"
+#include "build-defs.h"
+
+extern module *top_module;
+
+void php3_virtual(INTERNAL_FUNCTION_PARAMETERS);
+void php3_getallheaders(INTERNAL_FUNCTION_PARAMETERS);
+void php3_apachelog(INTERNAL_FUNCTION_PARAMETERS);
+void php3_info_apache(void);
+void php3_apache_note(INTERNAL_FUNCTION_PARAMETERS);
+void php3_apache_lookup_uri(INTERNAL_FUNCTION_PARAMETERS);
+
+function_entry apache_functions[] = {
+       {"virtual",                     php3_virtual,           NULL},
+       {"getallheaders",               php3_getallheaders,     NULL},
+       {"apache_note", php3_apache_note,NULL},
+       {"apache_lookup_uri", php3_apache_lookup_uri,NULL},
+       {NULL, NULL, NULL}
+};
+
+
+static PHP_INI_MH(OnChangeApacheInt)
+{
+       long *p;
+       char *base = (char *) &php_apache_info;
+
+       p = (long *) (base+(size_t) mh_arg);
+
+       if (new_value) {
+               *p = atoi(new_value);
+               return SUCCESS;
+       } else {
+               return FAILURE;
+       }
+}
+
+
+static PHP_INI_MH(OnChangeApacheString)
+{
+       char **p;
+       char *base = (char *) &php_apache_info;
+
+       p = (char **) (base+(size_t) mh_arg);
+
+       if (new_value) {
+               *p = new_value;
+               return SUCCESS;
+       } else {
+               return FAILURE;
+       }
+}
+
+PHP_INI_BEGIN()
+       PHP_INI_ENTRY("xbithack",                       "0",                            PHP_INI_ALL,            OnChangeApacheInt,              (void *) XtOffsetOf(php_apache_info_struct, xbithack))
+       PHP_INI_ENTRY("engine",                         "1",                            PHP_INI_ALL,            OnChangeApacheInt,              (void *) XtOffsetOf(php_apache_info_struct, engine))
+       PHP_INI_ENTRY("last_modified",          "0",                            PHP_INI_ALL,            OnChangeApacheInt,              (void *) XtOffsetOf(php_apache_info_struct, last_modified))
+       PHP_INI_ENTRY("dav_script",                     NULL,                           PHP_INI_ALL,            OnChangeApacheString,   (void *) XtOffsetOf(php_apache_info_struct, dav_script))
+PHP_INI_END()
+
+
+static int php_apache_minit(INIT_FUNC_ARGS)
+{
+       REGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+
+static int php_apache_mshutdown(SHUTDOWN_FUNC_ARGS)
+{
+       UNREGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+
+php3_module_entry apache_module_entry = {
+       "Apache", apache_functions, php_apache_minit, php_apache_mshutdown, NULL, NULL, php3_info_apache, STANDARD_MODULE_PROPERTIES
+};
+
+/* {{{ proto string apache_note(string note_name [, string note_value])
+   Get and set Apache request notes */
+void php3_apache_note(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *arg_name,*arg_val;
+       char *note_val;
+       int arg_count = ARG_COUNT(ht);
+TLS_VARS;
+
+       if (arg_count<1 || arg_count>2 ||
+               getParameters(ht,arg_count,&arg_name,&arg_val) == FAILURE ) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       convert_to_string(arg_name);
+       note_val = (char *) table_get(GLOBAL(php3_rqst)->notes,arg_name->value.str.val);
+       
+       if (arg_count == 2) {
+               convert_to_string(arg_val);
+               table_set(GLOBAL(php3_rqst)->notes,arg_name->value.str.val,arg_val->value.str.val);
+       }
+
+       if (note_val) {
+               RETURN_STRING(note_val,1);
+       } else {
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+void php3_info_apache(void) {
+       module *modp = NULL;
+#if !defined(WIN32) && !defined(WINNT)
+       char name[64];
+       char *p;
+#endif
+       server_rec *serv = GLOBAL(php3_rqst)->server;
+       extern char server_root[MAX_STRING_LEN];
+       extern uid_t user_id;
+       extern char *user_name;
+       extern gid_t group_id;
+       extern int max_requests_per_child;
+
+#if WIN32|WINNT
+       PUTS("Apache for Windows 95/NT<br>");
+#else
+       php3_printf("<tt>APACHE_INCLUDE=%s<br>\n", PHP_APACHE_INCLUDE);
+       php3_printf("APACHE_TARGET=%s<br></tt>\n", PHP_APACHE_TARGET);
+#endif
+       php3_printf("Apache Version: <b>%s</b><br>",SERVER_VERSION);
+#ifdef APACHE_RELEASE
+       php3_printf("Apache Release: <b>%d</b><br>",APACHE_RELEASE);
+#endif
+       php3_printf("Apache API Version: <b>%d</b><br>",MODULE_MAGIC_NUMBER);
+       php3_printf("Hostname/port: <b>%s:%u</b><br>\n",serv->server_hostname,serv->port);
+#if !defined(WIN32) && !defined(WINNT)
+       php3_printf("User/Group: <b>%s(%d)/%d</b><br>\n",user_name,(int)user_id,(int)group_id);
+       php3_printf("Max Requests: <b>per child: %d &nbsp;&nbsp; keep alive: %s &nbsp;&nbsp; max per connection: %d</b><br>\n",max_requests_per_child,serv->keep_alive ? "on":"off", serv->keep_alive_max);
+#endif
+       php3_printf("Timeouts: <b>connection: %d &nbsp;&nbsp; keep-alive: %d</b><br>",serv->timeout,serv->keep_alive_timeout);
+#if !defined(WIN32) && !defined(WINNT)
+       php3_printf("Server Root: <b>%s</b><br>\n",server_root);
+
+       PUTS("Loaded modules: ");
+       for(modp = top_module; modp; modp = modp->next) {
+               strncpy(name, modp->name, sizeof(name) - 1);
+               if ((p = strrchr(name, '.'))) {
+                       *p='\0'; /* Cut off ugly .c extensions on module names */
+               }
+               PUTS(name);
+               if (modp->next) {
+                       PUTS(", ");
+               }
+       }
+#endif
+       PUTS("<br></td?</tr>\n");
+}
+
+/* This function is equivalent to <!--#include virtual...-->
+ * in mod_include. It does an Apache sub-request. It is useful
+ * for including CGI scripts or .shtml files, or anything else
+ * that you'd parse through Apache (for .phtml files, you'd probably
+ * want to use <?Include>. This only works when PHP is compiled
+ * as an Apache module, since it uses the Apache API for doing
+ * sub requests.
+ */
+/* {{{ proto int virtual(string filename)
+   Perform an Apache sub-request */
+void php3_virtual(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *filename;
+       request_rec *rr = NULL;
+TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&filename) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string(filename);
+       
+       if (!(rr = sub_req_lookup_uri (filename->value.str.val, GLOBAL(php3_rqst)))) {
+               php3_error(E_WARNING, "Unable to include '%s' - URI lookup failed", filename->value.str.val);
+               if (rr) destroy_sub_req (rr);
+               RETURN_FALSE;
+       }
+
+       if (rr->status != 200) {
+               php3_error(E_WARNING, "Unable to include '%s' - error finding URI", filename->value.str.val);
+               if (rr) destroy_sub_req (rr);
+               RETURN_FALSE;
+       }
+
+       /* Cannot include another PHP file because of global conflicts */
+       if (rr->content_type &&
+               !strcmp(rr->content_type, PHP3_MIME_TYPE)) {
+               php3_error(E_WARNING, "Cannot include a PHP file "
+                         "(use <code>&lt;?include \"%s\"&gt;</code> instead)", filename->value.str.val);
+               if (rr) destroy_sub_req (rr);
+               RETURN_FALSE;
+       }
+
+       if (run_sub_req(rr)) {
+               php3_error(E_WARNING, "Unable to include '%s' - request execution failed", filename->value.str.val);
+               if (rr) destroy_sub_req (rr);
+               RETURN_FALSE;
+       } else {
+               if (rr) destroy_sub_req (rr);
+               RETURN_TRUE;
+       }
+}
+/* }}} */
+
+/* {{{ proto array getallheaders(void)
+   Fetch all HTTP request headers */
+void php3_getallheaders(INTERNAL_FUNCTION_PARAMETERS)
+{
+    array_header *env_arr;
+    table_entry *tenv;
+    int i;
+       
+    if (array_init(return_value) == FAILURE) {
+               RETURN_FALSE;
+    }
+    env_arr = table_elts(php3_rqst->headers_in);
+    tenv = (table_entry *)env_arr->elts;
+    for (i = 0; i < env_arr->nelts; ++i) {
+               if (!tenv[i].key ||
+                       (PG(safe_mode) &&
+                        !strncasecmp(tenv[i].key, "authorization", 13))) {
+                       continue;
+               }
+               if (add_assoc_string(return_value, tenv[i].key,(tenv[i].val==NULL) ? "" : tenv[i].val, 1)==FAILURE) {
+                       RETURN_FALSE;
+               }
+    }
+}
+/* }}} */
+
+/* {{{ proto class apache_lookup_uri(string URI)
+   Perform a partial request of the given URI to obtain information about it */
+void php3_apache_lookup_uri(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *filename;
+       request_rec *rr=NULL;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&filename) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string(filename);
+
+       if(!(rr = sub_req_lookup_uri(filename->value.str.val, GLOBAL(php3_rqst)))) {
+               php3_error(E_WARNING, "URI lookup failed", filename->value.str.val);
+               RETURN_FALSE;
+       }
+       object_init(return_value);
+       add_property_long(return_value,"status",rr->status);
+       if (rr->the_request) {
+               add_property_string(return_value,"the_request",rr->the_request,1);
+       }
+       if (rr->status_line) {
+               add_property_string(return_value,"status_line",rr->status_line,1);              
+       }
+       if (rr->method) {
+               add_property_string(return_value,"method",rr->method,1);                
+       }
+       if (rr->content_type) {
+               add_property_string(return_value,"content_type",(char *)rr->content_type,1);
+       }
+       if (rr->handler) {
+               add_property_string(return_value,"handler",(char *)rr->handler,1);              
+       }
+       if (rr->uri) {
+               add_property_string(return_value,"uri",rr->uri,1);
+       }
+       if (rr->filename) {
+               add_property_string(return_value,"filename",rr->filename,1);
+       }
+       if (rr->path_info) {
+               add_property_string(return_value,"path_info",rr->path_info,1);
+       }
+       if (rr->args) {
+               add_property_string(return_value,"args",rr->args,1);
+       }
+       if (rr->boundary) {
+               add_property_string(return_value,"boundary",rr->boundary,1);
+       }
+       add_property_long(return_value,"no_cache",rr->no_cache);
+       add_property_long(return_value,"no_local_copy",rr->no_local_copy);
+       add_property_long(return_value,"allowed",rr->allowed);
+       add_property_long(return_value,"sent_bodyct",rr->sent_bodyct);
+       add_property_long(return_value,"bytes_sent",rr->bytes_sent);
+       add_property_long(return_value,"byterange",rr->byterange);
+       add_property_long(return_value,"clength",rr->clength);
+
+#if MODULE_MAGIC_NUMBER >= 19980324
+       if (rr->unparsed_uri) {
+               add_property_string(return_value,"unparsed_uri",rr->unparsed_uri,1);
+       }
+       if(rr->mtime) {
+               add_property_long(return_value,"mtime",rr->mtime);
+       }
+#endif
+       if(rr->request_time) {
+               add_property_long(return_value,"request_time",rr->request_time);
+       }
+
+       destroy_sub_req(rr);
+}
+/* }}} */
+
+#if 0
+This function is most likely a bad idea.  Just playing with it for now.
+
+void php3_apache_exec_uri(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *filename;
+       request_rec *rr=NULL;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht,1,&filename) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string(filename);
+
+       if(!(rr = ap_sub_req_lookup_uri(filename->value.str.val, GLOBAL(php3_rqst)))) {
+               php3_error(E_WARNING, "URI lookup failed", filename->value.str.val);
+               RETURN_FALSE;
+       }
+       RETVAL_LONG(ap_run_sub_req(rr));
+       ap_destroy_sub_req(rr);
+}
+#endif
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/apache/config.m4 b/ext/apache/config.m4
new file mode 100644 (file)
index 0000000..e878cdb
--- /dev/null
@@ -0,0 +1,5 @@
+dnl $Id$
+
+if test -n "$APACHE_INCLUDE"; then
+    PHP_EXTENSION(apache)
+fi
diff --git a/ext/com/php3_COM.h b/ext/com/php3_COM.h
new file mode 100644 (file)
index 0000000..ed9cc4f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _PHP3_COM_H
+#define _PHP3_COM_H
+
+#if WIN32|WINNT
+
+extern int php3_minit_COM(INIT_FUNC_ARGS);
+extern int php3_mshutdown_COM(SHUTDOWN_FUNC_ARGS);
+extern void php3_COM_load(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_COM_invoke(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_FUNCTION(com_propget);
+PHP_FUNCTION(com_propput);
+extern php3_module_entry COM_module_entry;
+#define COM_module_ptr &COM_module_entry
+
+#else
+
+#define COM_module_ptr NULL
+
+#endif  /* Win32|WINNT */
+
+#endif  /* _PHP3_COM_H */
diff --git a/ext/hyperwave/DList.h b/ext/hyperwave/DList.h
new file mode 100644 (file)
index 0000000..e574638
--- /dev/null
@@ -0,0 +1,128 @@
+/****************************************************************************
+*
+*                                      Copyright (C) 1991 Kendall Bennett.
+*                                                      All rights reserved.
+*
+* Filename:            $RCSfile$
+* Version:             $Revision$
+*
+* Language:            ANSI C
+* Environment: any
+*
+* Description: Header file for doubly linked list routines.
+*
+* $Id$
+*
+* Revision History:
+* -----------------
+*
+* $Log$
+* Revision 1.1.1.1  1999/04/07 21:03:20  zeev
+* PHP 4.0
+*
+* Revision 1.1.1.1  1999/03/17 04:29:11  andi
+* PHP4
+*
+* Revision 1.1.1.1  1998/12/21 07:56:22  andi
+* Trying to start the zend CVS tree
+*
+* Revision 1.2  1998/08/14 15:51:12  shane
+* Some work on getting hyperwave to work on windows.  hg_comm needs a lot of work.
+*
+* Mainly, signals, fnctl, bzero, bcopy, etc are not portable functions.  Most of this
+* will have to be rewriten for windows.
+*
+* Revision 1.1  1998/08/12 09:29:16  steinm
+* First version of Hyperwave module.
+*
+* Revision 1.5  91/12/31  19:40:54  kjb
+* 
+* Modified include files directories.
+* 
+* Revision 1.4  91/09/27  03:10:41  kjb
+* Added compatibility with C++.
+* 
+* Revision 1.3  91/09/26  10:07:16  kjb
+* Took out extern references
+* 
+* Revision 1.2  91/09/01  19:37:20  ROOT_DOS
+* Changed DLST_TAIL macro so that it returns a pointer to the REAL last
+* node of the list, not the dummy last node (l->z).
+* 
+* Revision 1.1  91/09/01  18:38:23  ROOT_DOS
+* Initial revision
+* 
+****************************************************************************/
+
+#ifndef        __DLIST_H
+#define        __DLIST_H
+
+#ifndef        __DEBUG_H
+/*#include "debug.h"*/
+#endif
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+typedef struct DLST_BUCKET {
+       struct DLST_BUCKET      *next;
+       struct DLST_BUCKET      *prev;
+       } DLST_BUCKET;
+
+typedef struct {
+       int                     count;                  /* Number of elements currently in list */
+       DLST_BUCKET     *head;                  /* Pointer to head element of list              */
+       DLST_BUCKET     *z;                             /* Pointer to last node of list                 */
+       DLST_BUCKET     hz[2];                  /* Space for head and z nodes                   */
+       } DLIST;
+
+/* Return a pointer to the user space given the address of the header of
+ * a node.
+ */
+
+#define        DLST_USERSPACE(h)       ((void*)((DLST_BUCKET*)(h) + 1))
+
+/* Return a pointer to the header of a node, given the address of the
+ * user space.
+ */
+
+#define        DLST_HEADER(n)          ((DLST_BUCKET*)(n) - 1)
+
+/* Return a pointer to the user space of the list's head node. This user
+ * space does not actually exist, but it is useful to be able to address
+ * it to enable insertion at the start of the list.
+ */
+
+#define        DLST_HEAD(l)            DLST_USERSPACE((l)->head)
+
+/* Return a pointer to the user space of the last node in list.        */
+
+#define        DLST_TAIL(l)            DLST_USERSPACE((l)->z->prev)
+
+/* Determine if a list is empty
+ */
+
+#define        DLST_EMPTY(l)           ((l)->count == 0)
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *dlst_newnode(int size);
+void dlst_freenode(void *node);
+DLIST *dlst_init(void);
+void dlst_kill(DLIST *l,void (*freeNode)(void *node));
+void dlst_insertafter(DLIST *l,void *node,void *after);
+void *dlst_deletenext(DLIST *l,void *node);
+void *dlst_first(DLIST *l);
+void *dlst_last(DLIST *l);
+void *dlst_next(void *prev);
+void *dlst_prev(void *next);
+void dlst_mergesort(DLIST *l,int (*cmp_func)(void*,void*));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ext/hyperwave/Makefile.am b/ext/hyperwave/Makefile.am
new file mode 100644 (file)
index 0000000..c5be33e
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id$
+
+INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend
+noinst_LIBRARIES=libphpext_hyperwave.a
+libphpext_hyperwave_a_SOURCES=hw.c hg_comm.c
+
diff --git a/ext/hyperwave/config.h.stub b/ext/hyperwave/config.h.stub
new file mode 100644 (file)
index 0000000..d8e8bf4
--- /dev/null
@@ -0,0 +1,2 @@
+/* Define if you want Hyperwave support */
+#define HYPERWAVE 0
diff --git a/ext/hyperwave/config.m4 b/ext/hyperwave/config.m4
new file mode 100644 (file)
index 0000000..ef48f24
--- /dev/null
@@ -0,0 +1,18 @@
+dnl $Id$
+
+AC_MSG_CHECKING(for Hyperwave support)
+AC_ARG_WITH(hyperwave,
+[  --with-hyperwave        Include Hyperwave support],
+[
+  if test "$withval" != "no"; then
+    AC_DEFINE(HYPERWAVE,1)
+    AC_MSG_RESULT(yes)
+    PHP_EXTENSION(hyperwave)
+  else
+    AC_DEFINE(HYPERWAVE,0)
+    AC_MSG_RESULT(no)
+  fi
+],[
+  AC_DEFINE(HYPERWAVE,0)
+  AC_MSG_RESULT(no)
+])
diff --git a/ext/hyperwave/dlist.c b/ext/hyperwave/dlist.c
new file mode 100644 (file)
index 0000000..27c1305
--- /dev/null
@@ -0,0 +1,410 @@
+/****************************************************************************
+*
+*                                      Copyright (C) 1991 Kendall Bennett.
+*                                                      All rights reserved.
+*
+* Filename:            $RCSfile$
+* Version:             $Revision$
+*
+* Language:            ANSI C
+* Environment: any
+*
+* Description: Module to implement doubly linked lists. Includes a routine
+*                              to peform a mergesort on the doubly linked list.
+*
+* $Id$
+*
+* Revision History:
+* -----------------
+*
+* $Log$
+* Revision 1.1.1.1  1999/04/07 21:03:31  zeev
+* PHP 4.0
+*
+* Revision 1.1.1.1  1999/03/17 04:29:11  andi
+* PHP4
+*
+* Revision 1.1.1.1  1998/12/21 07:56:22  andi
+* Trying to start the zend CVS tree
+*
+* Revision 1.1  1998/08/12 09:29:16  steinm
+* First version of Hyperwave module.
+*
+* Revision 1.5  91/12/31  19:39:49  kjb
+* Modified include file directories.
+* 
+* Revision 1.4  91/10/28  03:16:39  kjb
+* Ported to the Iris.
+* 
+* Revision 1.3  91/09/27  03:09:18  kjb
+* Cosmetic change.
+* 
+* Revision 1.2  91/09/03  18:27:42  ROOT_DOS
+* Ported to UNIX.
+* 
+* Revision 1.1  91/09/01  18:35:23  ROOT_DOS
+* Initial revision
+* 
+****************************************************************************/
+
+#ifndef MSVC5
+#include "config.h"
+#endif
+
+#if HYPERWAVE
+
+#include <stdio.h>
+#include <malloc.h>
+#include <signal.h>
+#include "debug.h"
+#include "DList.h"
+
+PUBLIC void *dlst_newnode(int size)
+/****************************************************************************
+*
+* Function:            dlst_newnode
+* Parameters:  size    - Amount of memory to allocate for node
+* Returns:      Pointer to the allocated node's user space.
+*
+* Description: Allocates the memory required for a node, adding a small
+*                              header at the start of the node. We return a reference to
+*                              the user space of the node, as if it had been allocated via
+*                              malloc().
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *node;
+
+       if ( !(node = (DLST_BUCKET*)malloc(size + sizeof(DLST_BUCKET))) ) {
+               fprintf(stderr,"Not enough memory to allocate list node.\n");
+/*             raise(SIGABRT);*/
+               return NULL;
+               }
+
+       return DLST_USERSPACE(node);            /* Return pointer to user space */
+}
+
+PUBLIC void dlst_freenode(void *node)
+/****************************************************************************
+*
+* Function:            dlst_freenode
+* Parameters:  node    - Node to free.
+*
+* Description:  Frees a node previously allocated with lst_newnode().
+*
+****************************************************************************/
+{
+       free(DLST_HEADER(node));
+}
+
+PUBLIC DLIST *dlst_init(void)
+/****************************************************************************
+*
+* Function:            dlst_init
+* Returns:      Pointer to a newly created list.
+*
+* Description: Initialises a list and returns a pointer to it.
+*
+****************************************************************************/
+{
+       DLIST   *l;
+
+       if ((l = (DLIST*)malloc(sizeof(DLIST))) != NULL) {
+               l->count = 0;
+               l->head = &(l->hz[0]);
+               l->z = &(l->hz[1]);
+               l->head->next = l->z->next = l->z;
+               l->z->prev = l->head->prev = l->head;
+               }
+       else {
+               fprintf(stderr,"Insufficient memory to allocate list\n");
+               /*raise(SIGABRT);*/
+               return NULL;
+               }
+
+       return l;
+}
+
+PUBLIC void dlst_kill(DLIST *l,void (*freeNode)(void *node))
+/****************************************************************************
+*
+* Function:            dlst_kill
+* Parameters:  l                       - List to kill
+*                              freeNode        - Pointer to user routine to free a node
+*
+* Description: Kills the list l, by deleting all of the elements contained
+*                              within the list one by one and then deleting the list
+*                              itself. Note that we call the user supplied routine
+*                              (*freeNode)() to free each list node. This allows the user
+*                              program to perform any extra processing needed to kill each
+*                              node (if each node contains pointers to other items on the
+*                              heap for example). If no extra processing is required, just
+*                              pass the address of dlst_freenode(), ie:
+*
+*                                      dlst_kill(myList,dlst_freenode);
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n,*p;
+
+       n = l->head->next;
+       while (n != l->z) {                     /* Free all nodes in list                               */
+               p = n;
+               n = n->next;
+               (*freeNode)(DLST_USERSPACE(p));
+               }
+       free(l);                                        /* Free the list itself                                 */
+}
+
+PUBLIC void dlst_insertafter(DLIST *l,void *node,void *after)
+/****************************************************************************
+*
+* Function:            lst_insertafter
+* Parameters:  l               - List to insert node into
+*                              node    - Pointer to user space of node to insert
+*                              after   - Pointer to user space of node to insert node after
+*
+* Description: Inserts a new node into the list after the node 'after'. To
+*                              insert a new node at the beginning of the list, user the
+*                              macro DLST_HEAD in place of 'after'. ie:
+*
+*                                      dlst_insertafter(mylist,node,DLST_HEAD(mylist));
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n = DLST_HEADER(node),*a = DLST_HEADER(after);
+
+       n->next = a->next;
+       a->next = n;
+       n->prev = a;
+       n->next->prev = n;
+       l->count++;
+}
+
+PUBLIC void *dlst_deletenext(DLIST *l,void *node)
+/****************************************************************************
+*
+* Function:            lst_deletenext
+* Parameters:  l               - List to delete node from.
+*                              node    - Node to delete the next node from
+* Returns:             Pointer to the deleted node's userspace.
+*
+* Description: Removes the node AFTER 'node' from the list l.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n = DLST_HEADER(node);
+
+       node = DLST_USERSPACE(n->next);
+       n->next->next->prev = n;
+       n->next = n->next->next;
+       l->count--;
+       return node;
+}
+
+PUBLIC void *dlst_first(DLIST *l)
+/****************************************************************************
+*
+* Function:            dlst_first
+* Parameters:  l               - List to obtain first node from
+* Returns:             Pointer to first node in list, NULL if list is empty.
+*
+* Description: Returns a pointer to the user space of the first node in
+*                              the list. If the list is empty, we return NULL.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n;
+
+       n = l->head->next;
+       return (n == l->z ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_last(DLIST *l)
+/****************************************************************************
+*
+* Function:            dlst_last
+* Parameters:  l       - List to obtain last node from
+* Returns:             Pointer to last node in list, NULL if list is empty.
+*
+* Description: Returns a pointer to the user space of the last node in
+*                              the list. If the list is empty, we return NULL.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n;
+
+       n = l->z->prev;
+       return (n == l->head ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_next(void *prev)
+/****************************************************************************
+*
+* Function:            dlst_next
+* Parameters:  prev    - Previous node in list to obtain next node from
+* Returns:             Pointer to the next node in the list, NULL at end of list.
+*
+* Description: Returns a pointer to the user space of the next node in the
+*                              list given a pointer to the user space of the previous node.
+*                              If we have reached the end of the list, we return NULL. The
+*                              end of the list is detected when the next pointer of a node
+*                              points back to itself, as does the dummy last node's next
+*                              pointer. This enables us to detect the end of the list
+*                              without needed access to the list data structure itself.
+*
+*                              NOTE:   We do no checking to ensure that 'prev' is NOT a
+*                                              NULL pointer.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n = DLST_HEADER(prev);
+
+       n = n->next;
+       return (n == n->next ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_prev(void *next)
+/****************************************************************************
+*
+* Function:            dlst_prev
+* Parameters:  next    - Next node in list to obtain previous node from
+* Returns:             Pointer to the previous node in the list, NULL at start list.
+*
+* Description: Returns a pointer to the user space of the prev node in the
+*                              list given a pointer to the user space of the next node.
+*                              If we have reached the start of the list, we return NULL. The
+*                              start of the list is detected when the prev pointer of a node
+*                              points back to itself, as does the dummy head node's prev
+*                              pointer. This enables us to detect the start of the list
+*                              without needed access to the list data structure itself.
+*
+*                              NOTE:   We do no checking to ensure that 'next' is NOT a
+*                                              NULL pointer.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *n = DLST_HEADER(next);
+
+       n = n->prev;
+       return (n == n->prev ? NULL : DLST_USERSPACE(n));
+}
+
+/* Static globals required by merge()  */
+
+static DLST_BUCKET     *z;
+static int                     (*cmp)(void*,void*);
+
+PRIVATE DLST_BUCKET *merge(DLST_BUCKET *a,DLST_BUCKET *b,DLST_BUCKET **end)
+/****************************************************************************
+*
+* Function:            merge
+* Parameters:  a,b             - Sublist's to merge
+* Returns:             Pointer to the merged sublists.
+*
+* Description: Merges two sorted lists of nodes together into a single
+*                              sorted list.
+*
+****************************************************************************/
+{
+       DLST_BUCKET     *c;
+
+       /* Go through the lists, merging them together in sorted order  */
+
+       c = z;
+       while (a != z && b != z) {
+               if ((*cmp)(DLST_USERSPACE(a),DLST_USERSPACE(b)) <= 0) {
+                       c->next = a; c = a; a = a->next;
+                       }
+               else {
+                       c->next = b; c = b; b = b->next;
+                       }
+               };
+
+       /* If one of the lists is not exhausted, then re-attach it to the end
+        * of the newly merged list
+        */
+
+       if (a != z) c->next = a;
+       if (b != z) c->next = b;
+
+       /* Set *end to point to the end of the newly merged list        */
+
+       while (c->next != z) c = c->next;
+       *end = c;
+
+       /* Determine the start of the merged lists, and reset z to point to
+        * itself
+        */
+
+       c = z->next; z->next = z;
+       return c;
+}
+
+PUBLIC void dlst_mergesort(DLIST *l,int (*cmp_func)(void*,void*))
+/****************************************************************************
+*
+* Function:            dlst_mergesort
+* Parameters:  l                       - List to merge sort
+*                              cmp_func        - Function to compare two user spaces
+*
+* Description: Mergesort's all the nodes in the list. 'cmp' must point to
+*                              a comparison function that can compare the user spaces of
+*                              two different nodes. 'cmp' should work the same as
+*                              strcmp(), in terms of the values it returns. Rather than
+*                              waste processing time keeping the previous pointers up to
+*                              date while performing the mergesort, we simply run through
+*                              the list at the end of the sort to fix the previous pointers.
+*
+****************************************************************************/
+{
+       int                     i,N;
+       DLST_BUCKET     *a,*b;          /* Pointers to sublists to merge                        */
+       DLST_BUCKET     *c;                     /* Pointer to end of sorted sublists            */
+       DLST_BUCKET     *head;          /* Pointer to dummy head node for list          */
+       DLST_BUCKET     *todo;          /* Pointer to sublists yet to be sorted         */
+       DLST_BUCKET     *t;                     /* Temporary                                                            */
+
+       /* Set up globals required by merge() and pointer to head       */
+
+       z = l->z; cmp = cmp_func; head = l->head;
+
+       for (N = 1,a = z; a != head->next; N = N + N) {
+               todo = head->next; c = head;
+               while (todo != z) {
+
+                       /* Build first sublist to be merged, and splice from main list
+                        */
+
+                       a = t = todo;
+                       for (i = 1; i < N; i++) t = t->next;
+                       b = t->next; t->next = z; t = b;
+
+                       /* Build second sublist to be merged and splice from main list
+                        */
+
+                       for (i = 1; i < N; i++) t = t->next;
+                       todo = t->next; t->next = z;
+
+                       /* Merge the two sublists created, and set 'c' to point to the
+                        * end of the newly merged sublists.
+                        */
+
+                       c->next = merge(a,b,&t); c = t;
+                       }
+               }
+
+       /* Fix the previous pointers for the list       */
+
+       a = b = l->head;
+       b = b->next;
+       while (1) {
+               b->prev = a;
+               if (b == z)
+                       break;
+               a = a->next;
+               b = b->next;
+               }
+}
+
+#endif
diff --git a/ext/hyperwave/hg_comm.c b/ext/hyperwave/hg_comm.c
new file mode 100644 (file)
index 0000000..171ea9e
--- /dev/null
@@ -0,0 +1,4701 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of the GNU General Public License as published by |
+   | the Free Software Foundation; either version 2 of the License, or    |
+   | (at your option) any later version.                                  |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            |
+   +----------------------------------------------------------------------+
+   | Authors: Uwe Steinmann                                               |
+   |                                                                      |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* #define HW_DEBUG */
+
+#include <stdlib.h>
+
+#if WIN32|WINNT
+#include "win95nt.h"
+#else
+#include "config.h"
+#endif
+
+#if HYPERWAVE
+
+#include <stdio.h>
+#include <string.h> 
+#include <sys/types.h>
+#if WIN32|WINNT
+# include <winsock2.h>
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# define ETIMEDOUT WSAETIMEDOUT
+# define bcopy memcpy
+# define bzero(a,b) memset(a,0,b)
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netdb.h>
+# include <unistd.h>
+# include <sys/param.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <alloc.h>
+#include "hg_comm.h"
+#include "DList.h"
+#include "php.h"
+#include "head.h"
+
+static int set_nonblocking(int fd);
+static int set_blocking(int fd);
+
+static int hg_read_exact(int sockfd, char *buf, int size);
+static int hg_read(int sockfd, char *buf, int size);
+static int hg_write(int sockfd, char *buf, int size);
+
+static int   send_hg_msg(int sockfd, hg_msg *msg, int length);
+static void  build_msg_header(hg_msg *msg, int length, int version_msgid, int msg_type);
+static char *build_msg_int(char *buf, int val);
+static char *build_msg_str(char *buf, char *str);
+static int   swap(int val);
+
+
+int version      = VERSION;
+/* F_DISTRIBUTED has the effect that all object ids are
+   virtual. This means whenever an object is requested a
+   new id is generated for this session. Wavemaster and
+   Harmony set this flag. How do I know? tcpdump tells
+   a lot if investigate the output.
+  int version      = VERSION | F_DISTRIBUTED; */
+/* int version   = VERSION | F_DISTRIBUTED | F_COMPRESSED; */
+static int msgid        =  1;
+static int sock_flags   = -1;
+static int non_blocking =  0;
+static int swap_on = 0;
+static int rtimeout = 40;
+static int wtimeout = 40;
+static int lowerror = 0;
+
+/***********************************************************************
+* Function fnInsStr()                                                  *
+*                                                                      *
+* Insert string in string at position. The old string will be freed    *
+* with efree!!! The new string is allocated with malloc.               *
+* Parameter: string *str: string in which insstr is to be inserted     *
+*            int pos: Position where string is to inserted (0=first)   *
+*            string *insstr: string to be inserted                     *
+* Return: pointer to new string or NULL. If NULL is returned the       *
+*         memory for the old string has not been freed.                *
+***********************************************************************/
+char *fnInsStr(char *str, int pos, char *insstr)
+{
+       char *newstr, *ptr;
+
+       if((str == NULL) || (insstr == NULL))
+               return NULL;
+       if(pos > (int)strlen(str))
+               return NULL;
+
+       if(insstr[0] == '\0')
+               return str;
+
+       if(NULL == (newstr = malloc(strlen(str) + strlen(insstr) + 1))) {
+               lowerror = LE_MALLOC;
+               return NULL;
+               }
+
+       ptr = newstr;
+       memcpy(newstr, str, pos);
+       ptr += pos;
+       strcpy(ptr, insstr);
+       ptr += strlen(insstr);
+       strcpy(ptr, str+pos);
+
+       free(str);
+       return newstr;
+}
+
+/***********************************************************************
+* Function fnAddAnchor()                                               *
+*                                                                      *
+* Inserts new anchor into anchor list.                                 *
+* Parameter: DLIST pList: Anchor list                                  *
+*            int objectID: object ID of Anchor                         *
+*            int start: start position                                 *
+*            int end: end position                                     *
+* Return: Pointer to new anchor, NULL if error                         *
+***********************************************************************/
+ANCHOR *fnAddAnchor(DLIST *pAnchorList, 
+                    int objectID,
+                    int start, int end)
+{
+       ANCHOR *cur_ptr;
+
+       if((cur_ptr = (ANCHOR *) dlst_newnode(sizeof(ANCHOR))) == NULL) {
+               return NULL;
+       }
+
+       memset(cur_ptr, 0, sizeof(ANCHOR));
+       cur_ptr->start = start;
+       cur_ptr->end = end;
+       cur_ptr->id = objectID;
+       cur_ptr->destdocname = NULL;
+       cur_ptr->nameanchor = NULL;
+       cur_ptr->link = NULL;
+       cur_ptr->tagattr = NULL;
+       cur_ptr->htmlattr = NULL;
+       cur_ptr->codebase = NULL;
+       cur_ptr->code = NULL;
+       cur_ptr->keyword = NULL;
+       cur_ptr->fragment = NULL;
+
+       dlst_insertafter(pAnchorList, cur_ptr, DLST_HEAD(pAnchorList));
+
+       return(cur_ptr);
+}
+
+/***********************************************************************
+* Function fnDeleteAnchor()                                            *
+*                                                                      *
+* Inserts new anchor into anchor list.                                 *
+* Parameter: ptr: pointer to node                                      *
+* Return: void                                                         *
+***********************************************************************/
+void fnDeleteAnchor(ANCHOR *ptr)
+{
+
+       if(ptr->destdocname) efree(ptr->destdocname);
+       if(ptr->nameanchor) efree(ptr->nameanchor);
+       if(ptr->link) efree(ptr->link);
+       if(ptr->tagattr) efree(ptr->tagattr);
+       if(ptr->htmlattr) efree(ptr->htmlattr);
+       if(ptr->codebase) efree(ptr->codebase);
+       if(ptr->code) efree(ptr->code);
+       if(ptr->keyword) efree(ptr->keyword);
+       if(ptr->fragment) efree(ptr->fragment);
+
+       dlst_freenode(ptr);
+}
+
+/***********************************************************************
+* Function fnCmpAnchors()                                              *
+*                                                                      *
+* Compares to Anchors by its start position                            *
+* Parameter: ANCHOR a1: First Anchor                                   *
+*            ANCHOR a2: Second Anchor                                  *
+* Return: As strcmp                                                    *
+***********************************************************************/
+int fnCmpAnchors(ANCHOR *a1, ANCHOR *a2)
+{
+       if(a1->start < a2->start)
+               return -1;
+       if(a1->start == a2->start) {
+               /* It's importent to check this case as well, because a link with
+               a bigger end has to be inserted first.
+               */
+               if(a1->end < a2->end)
+                       return -1;
+               /* If both start and end are equal (yes, it is possible)
+                  we will Src Anchor before a Dest anchor. There has been
+                  a case where an IMG was surrounded by a NAME which was
+                  surrounded by a HREF. In such a case the HREF doesn't
+                  work.
+               */
+               if(a1->end == a2->end) {
+                       if(a1->tanchor > a2->tanchor)
+                               return -1;
+               }
+       }
+
+       return 1;
+}
+
+/***********************************************************************
+* Function fnCreateAnchorList()                                        *
+*                                                                      *
+* Returns a list of Anchors converted from an object record            *
+* Parameter: char **anchors: object records of anchors                 *
+*            char **dest: object records of destinations               *
+*            int ancount: number of anchors                            *
+* Return: List of Anchors, NULL if error                               *
+***********************************************************************/
+DLIST *fnCreateAnchorList(char **anchors, char **docofanchorrec, char **reldestrec, int ancount, int anchormode)
+{
+       int start, end, i, destid, anchordestid, objectID;
+       ANCHOR *cur_ptr = NULL;
+       DLIST *pAnchorList = dlst_init();
+
+       for(i=ancount-1; i>=0; i--) {
+               char *object = NULL;
+               char *docofanchorptr = NULL;
+               char *reldestptr = NULL;
+               char *str, *str1, link[200];
+
+               if(NULL != anchors[i]) {
+                       object = anchors[i];
+                       docofanchorptr = docofanchorrec[i];
+                       reldestptr = reldestrec[i];
+       
+                       /* Determine Position. Doesn't matter if Src or Dest */
+                       str = strstr(object, "Position");
+                       str += 9;
+                       sscanf(str, "0x%X 0x%X", &start, &end);
+       
+                       /* Determine ObjectID */
+                       objectID = 0;
+                       if(NULL != (str = strstr(object, "ObjectID"))) {
+                               str += 9;
+                               sscanf(str, "0x%X", &objectID);
+                       }
+       
+                       cur_ptr = fnAddAnchor(pAnchorList, objectID, start, end);
+       
+                       /* Determine Type of Anchor */
+                       str = strstr(object, "TAnchor");
+                       str += 8;
+                       if(*str == 'S') {
+                               char destdocname[200];
+                               char nameanchor[200];
+                               cur_ptr->tanchor = 1;
+       
+                               cur_ptr->destdocname = NULL;
+                               if(NULL != (str = strstr(object, "Dest"))) {
+                                       char *tempptr;
+
+                                       /* No need to care about the value of Dest, because we take the info
+                                          from docofanchorptr.
+                                          Since the anchor has a destination there are two possibilities.
+                                          1. The destination is an anchor or
+                                          2. or the destination is a document already.
+                                          In both cases docofanchorptr has the proper info because GETDOCBYANCHOR
+                                          is such a nice message.
+                                       */
+                                       switch(anchormode) {
+                                               case 0:
+                                                       tempptr = docofanchorptr;
+                                                       break;
+                                               default:
+                                                       tempptr = reldestptr;
+                                       }
+                                       if(NULL != tempptr) {
+                                               /* It's always nice to deal with names, so let's first check
+                                                       for a name. If there is none we take the ObjectID.
+                                               */
+                                               if(NULL != (str = strstr(tempptr, "Name="))) {
+                                                       str += 5;
+                                               } else if(NULL != (str = strstr(tempptr, "ObjectID="))) {
+                                                       str += 9;
+                                               }
+                                               if(sscanf(str, "%s\n", destdocname)) {
+                                                       cur_ptr->destdocname = estrdup(destdocname);
+                                               }
+                                               destid = 0;
+                                               if(NULL != (str = strstr(tempptr, "ObjectID="))) {
+                                                       str += 9;
+                                                       sscanf(str, "0x%X", &destid);
+                                               }
+                                       }
+                               }
+       
+                               /* Get the Id of the anchor destination and the document id that belongs
+                                  to that anchor. We need that soon in order to determine if the anchor
+                                  points to a document or a dest anchor in a document.
+                               */
+                               anchordestid = 0;
+                               if(NULL != (str = strstr(object, "Dest="))) {
+                                       str += 5;
+                                       sscanf(str, "0x%X", &anchordestid);
+                               }
+                               
+                               /* if anchordestid != destid then the destination is an anchor in a document whose
+                                  name (objectID) is already in destdocname. We will have to extend the link
+                                  by '#...'
+                               */
+                               cur_ptr->nameanchor = NULL;
+                               if(anchordestid != destid) {
+                                       if(NULL != (str = strstr(object, "Dest="))) {
+                                               str += 5;
+                                               if(sscanf(str, "%s\n", nameanchor))
+                                                       cur_ptr->nameanchor = estrdup(nameanchor);
+                                       }
+                               }
+       
+                               if(!cur_ptr->destdocname) {
+                               cur_ptr->link = NULL;
+                               if(NULL != (str = strstr(object, "Hint=URL:"))) {
+                                       str += 9;
+                                       if(sscanf(str, "%s\n", link))
+                                               cur_ptr->link = estrdup(link);
+                               } else if(NULL != (str = strstr(object, "Hint="))) {
+                                       str += 5;
+                                       if(sscanf(str, "%s\n", link))
+                                               cur_ptr->link = estrdup(link);
+                               }
+                               }
+       
+                               cur_ptr->fragment = NULL;
+                               if(NULL != (str = strstr(object, "Fragment="))) {
+                                       str += 9;
+                                       if(sscanf(str, "%s\n", link))
+                                               cur_ptr->fragment = estrdup(link);
+                               }
+       
+                               cur_ptr->htmlattr = NULL;
+                               if(NULL != (str = strstr(object, "HtmlAttr="))) {
+                                       str += 9;
+                                       str1 = str;
+                                       while((*str1 != '\n') && (*str1 != '\0'))
+                                               str1++;
+                                       cur_ptr->htmlattr = emalloc(str1 - str + 1);
+                                       strncpy(cur_ptr->htmlattr, str, str1 - str);
+                                       cur_ptr->htmlattr[str1 - str] = '\0';
+                               }
+       
+                               if(NULL != (str = strstr(object, "LinkType="))) {
+                                       str += 9;
+                                       if(strncmp(str, "background", 10) == 0)
+                                               cur_ptr->linktype=HW_BACKGROUND_LINK;
+                                       else
+                                       if(strncmp(str, "intag", 5) == 0) {
+                                               cur_ptr->linktype=HW_INTAG_LINK;
+                                               cur_ptr->tagattr = NULL;
+                                               if(NULL != (str = strstr(object, "TagAttr="))) {
+                                                       str += 8;
+                                                       str1 = str;
+                                                       while((*str1 != '\n') && (*str1 != '\0'))
+                                                               str1++;
+                                                       cur_ptr->tagattr = emalloc(str1 - str + 1);
+                                                       memcpy(cur_ptr->tagattr, str, str1 - str);
+                                                       cur_ptr->tagattr[str1 - str] = '\0';
+                                               }
+                                       } else
+                                       if(strncmp(str, "applet", 6) == 0) {
+                                               cur_ptr->linktype=HW_APPLET_LINK;
+                                               cur_ptr->codebase = NULL;
+                                               if(NULL != (str = strstr(object, "CodeBase="))) {
+                                                       str += 9;
+                                                       str1 = str;
+                                                       while((*str1 != '\n') && (*str1 != '\0'))
+                                                               str1++;
+                                                       cur_ptr->codebase = emalloc(str1 - str + 1);
+                                                       memcpy(cur_ptr->codebase, str, str1 - str);
+                                                       cur_ptr->codebase[str1 - str] = '\0';
+                                               }
+                                               cur_ptr->code = NULL;
+                                               if(NULL != (str = strstr(object, "Code="))) {
+                                                       str += 5;
+                                                       str1 = str;
+                                                       while((*str1 != '\n') && (*str1 != '\0'))
+                                                               str1++;
+                                                       cur_ptr->code = emalloc(str1 - str + 1);
+                                                       memcpy(cur_ptr->code, str, str1 - str);
+                                                       cur_ptr->code[str1 - str] = '\0';
+                                               }
+                                       } else
+                                               cur_ptr->linktype=HW_DEFAULT_LINK;
+                               } else
+                                       cur_ptr->linktype=HW_DEFAULT_LINK;
+       
+                       } else { /* Destination Anchor */
+                               char nameanchor[200];
+       
+                               cur_ptr->tanchor = 2;
+                               cur_ptr->link = NULL;
+       
+                               /* Here is the only additional info for the name attribute */
+                               cur_ptr->nameanchor = NULL;
+                               if(NULL != (str = strstr(object, "ObjectID="))) {
+                                       str += 9;
+                                       if(sscanf(str, "%s\n", nameanchor))
+                                               cur_ptr->nameanchor = estrdup(nameanchor);
+                               }
+       
+                               cur_ptr->keyword = NULL;
+                               if(NULL != (str = strstr(object, "Keyword="))) {
+                                       str += 8;
+                                       if(sscanf(str, "%s\n", nameanchor))
+                                               cur_ptr->keyword = estrdup(nameanchor);
+                               }
+       
+                       }
+       
+                       efree(anchors[i]);
+                       if(docofanchorrec[i]) efree(docofanchorrec[i]);
+                       if(reldestrec[i]) efree(reldestrec[i]);
+               }
+       }
+       return pAnchorList;
+}
+
+/***********************************************************************
+* Function fnInsAnchorsIntoText()                                      *
+*                                                                      *
+* Returns the text document with all anchors inserted form list        *
+* Parameter: char *text: text without anchors                          *
+*            DList *pAnchorList: list of anchors                       *
+* Return: Text with anchors                                            *
+***********************************************************************/
+char *fnInsAnchorsIntoText(char *text, DLIST *pAnchorList, char **bodytag) {
+       ANCHOR *cur_ptr;
+       char bgstr[100], istr[200];
+       char *scriptname;
+       char *newtext;
+       int offset = 0;
+       int laststart=0;
+
+#if APACHE
+       {
+       int j;
+       array_header *arr = table_elts(GLOBAL(php3_rqst)->subprocess_env);
+       table_entry *elts = (table_entry *)arr->elts;
+
+       for (j=0; j < arr->nelts; j++) {
+               if(0 == strcmp(elts[j].key, "SCRIPT_NAME"))
+               break;
+       }
+       scriptname = elts[j].val;
+       }
+#else
+       scriptname = getenv("SCRIPT_FILENAME");
+#endif
+
+       newtext = text;
+       bgstr[0] = '\0';
+       dlst_mergesort(pAnchorList, fnCmpAnchors);
+
+       cur_ptr = (ANCHOR *) dlst_last(pAnchorList);
+       while(NULL != cur_ptr) {
+               istr[0] = '\0';
+               if(cur_ptr->tanchor == 1) { /* Src Anchor */
+                       if(laststart >= cur_ptr->end)
+                               offset = 0;
+                       if((cur_ptr->link != NULL) && (cur_ptr->link[0] != '\0')) {
+                               /* The link is only set if the Link points to an external document */
+                               switch(cur_ptr->linktype) {
+                                       case HW_BACKGROUND_LINK:
+                                               sprintf(bgstr, " background='%s'", cur_ptr->link);
+                                               break;
+                                       case HW_INTAG_LINK:
+                                               sprintf(istr, " %s='%s' start=%d", cur_ptr->tagattr, cur_ptr->link, cur_ptr->start);
+                                               offset -= 4; /* because there is no closing tag </A> */
+/*                                             laststart = cur_ptr->start; */
+                                               break;
+                                       case HW_APPLET_LINK:
+                                               if(cur_ptr->codebase)
+                                                 sprintf(istr, " CODEBASE='%s' CODE='%s'", cur_ptr->codebase, cur_ptr->code);
+                                               else
+                                                 sprintf(istr, " CODEBASE='/' CODE='%s'", cur_ptr->code);
+                                               break;
+                                       default:
+                                               newtext = fnInsStr(newtext, cur_ptr->end+offset, "</A>");
+                                               sprintf(istr, "<A HREF='%s' %s offset=%d>", cur_ptr->link, cur_ptr->htmlattr == NULL ? "" : cur_ptr->htmlattr, offset);
+                               }
+                       } else {
+                               switch(cur_ptr->linktype) {
+                                       case HW_BACKGROUND_LINK:
+                                               if(NULL != cur_ptr->destdocname)
+                                                       sprintf(bgstr, " background='%s/%s'", scriptname == NULL ? "" : scriptname, cur_ptr->destdocname);
+                                               else
+                                                       sprintf(bgstr, "");
+                                               break;
+                                       case HW_INTAG_LINK:
+                                               if(cur_ptr->fragment)
+/*                                                     sprintf(istr, " %s='%s/%s#%s'", cur_ptr->tagattr, scriptname == NULL ? "." : scriptname, cur_ptr->destdocname, cur_ptr->fragment);*/
+                                                       sprintf(istr, " %s='#%s'", cur_ptr->tagattr, cur_ptr->fragment);
+                                               else
+                                                       sprintf(istr, " %s='%s/%s'", cur_ptr->tagattr, scriptname == NULL ? "." : scriptname, cur_ptr->destdocname);
+                                               offset -= 4; /* because there is no closing tag </A> */
+/*                                             laststart = cur_ptr->start; */
+                                               break;
+                                       case HW_APPLET_LINK:
+                                               if(cur_ptr->codebase)
+/*                                               sprintf(istr, " CODEBASE='%s%s' CODE='%s'", scriptname == NULL ? "" : scriptname, cur_ptr->codebase, cur_ptr->code); */
+                                                 sprintf(istr, " CODEBASE='%s' CODE='%s'", cur_ptr->codebase, cur_ptr->code);
+                                               else
+                                                 sprintf(istr, " CODEBASE='/' CODE='%s'", cur_ptr->code);
+                                               break;
+                                       default:
+                                               newtext = fnInsStr(newtext, cur_ptr->end+offset, "</A>");
+
+                                               if(cur_ptr->nameanchor)
+                                                       sprintf(istr, "<A HREF='%s/%s#%s' %s>", scriptname == NULL ? "schade" : scriptname, cur_ptr->destdocname, cur_ptr->nameanchor, cur_ptr->htmlattr == NULL ? "" : cur_ptr->htmlattr);
+                                               else
+                                               if(cur_ptr->fragment)
+                                                       sprintf(istr, "<A HREF='%s/%s#%s' %s>", scriptname == NULL ? "" : scriptname, cur_ptr->destdocname, cur_ptr->fragment, cur_ptr->htmlattr == NULL ? "" : cur_ptr->htmlattr);
+                                               else
+                                                       sprintf(istr, "<A HREF='%s/%s' %s offset=%d>", scriptname == NULL ? "" : scriptname, cur_ptr->destdocname, cur_ptr->htmlattr == NULL ? "" : cur_ptr->htmlattr, offset);
+                               }
+                       }
+                       newtext = fnInsStr(newtext, cur_ptr->start, istr);
+                       /* In case there are several TAGS nested, we accumulate the offset 
+                          You wonder what the 4 means? It's the length of </A> */
+                       offset += strlen(istr) + 4;
+                       laststart = cur_ptr->start;
+               } else {
+                       if(laststart >= cur_ptr->end)
+                               offset = 0;
+                       newtext = fnInsStr(newtext, cur_ptr->end+offset, "</a>");
+
+                       /* If we have a keyword, we assume we had a fragment which has been used
+                          instead of the destdocname
+                       */
+                       if(cur_ptr->keyword)
+                               sprintf(istr, "<A NAME='%s'>", cur_ptr->keyword);
+                       else if(cur_ptr->nameanchor)
+                               sprintf(istr, "<A NAME='%s'>", cur_ptr->nameanchor);
+                       newtext = fnInsStr(newtext, cur_ptr->start, istr);
+                       /* In case there are several TAGS nested, we accumulate the offset
+                          You wonder what the 4 means? It's the length of </A> */
+                       offset += strlen(istr) + 4;
+                       laststart = cur_ptr->start;
+               }
+               cur_ptr = (ANCHOR *) dlst_prev(cur_ptr);
+       }
+       sprintf(istr, "<BODY %s>", bgstr);
+       *bodytag = estrdup(istr);
+       return(newtext);
+}
+       
+/***********************************************************************
+* Function fnAttributeValue()                                          *
+*                                                                      *
+* Returns the value of an attribute                                    *
+* Parameter: char *object: object record                               *
+*            char *attrname: attribute name                            *
+* Return: char*: attribute value, NULL if name not found               *
+***********************************************************************/
+char *fnAttributeValue(char *object, char *attrname)
+{
+       char *str, *str1, *attrvalue;
+       int len;
+
+       str = strstr(object, attrname);
+       if(NULL == str)
+               return(NULL);
+       str += strlen(attrname);
+       str++;
+       str1 = str;
+       while((*str1 != '\0') && (*str1 != '\n'))
+               str1++;
+       len = str1 - str;
+       if(NULL == (attrvalue = emalloc(len+1))) {
+               lowerror = LE_MALLOC;
+               return NULL;
+               }
+       memcpy(attrvalue, str, len);
+       attrvalue[len] = '\0';
+       return(attrvalue);
+}
+
+/***********************************************************************
+* Function fnAttributeCompare()                                        *
+*                                                                      *
+* Checks if an attribute in an objrec has a certain value              *
+* Parameter: char *object: object record                               *
+*            char *attrname: attribute name                            *
+*            char *value: value of attribute                           *
+* Return: char*: as strcmp                                             *
+***********************************************************************/
+int fnAttributeCompare(char *object, char *attrname, char *value)
+{
+       char *str, *str1;
+       int len;
+
+       if((NULL == object) || (NULL == attrname) || (NULL == value))
+               return -2;
+
+       /* Find the attribute Name and make sure it is followed by
+          a '=' sign and preceded by a '\n';
+       */
+       str = strstr(object, attrname);
+       if((NULL == str) ||
+          (str[strlen(attrname)] != '=') ||
+          (str[-1] != '\n')) {
+               return(-2);
+       }
+       str += strlen(attrname); /* skip the attribute name */
+       str++; /* skip the equal sign */
+
+       /* Search for end of attribute value */
+       str1 = str;
+       while((*str1 != '\0') && (*str1 != '\n'))
+               str1++;
+       len = str1 - str;
+       return(strncmp(str, value, len));
+}
+
+/*********************************************************************
+* Function fnCOpenDataCon()                                          *
+*                                                                    *
+* Opens data connection on client side. This function is called      *
+* right after the client has requested any data from the server      *
+* Parameter: int sockfd: socket of control connection                *
+*            int *port: port of control und data connection          *
+* Return   : sockfd on success, <0 if error                          *
+*********************************************************************/
+static int fnCOpenDataCon(int sockfd, int *port)
+  {
+  int fd;
+  struct sockaddr_in  serv_addr;
+  int len;
+  int option = 1;
+
+/*  len = sizeof(com_addr);
+  if(getsockname(sockfd, (struct sockaddr *) &com_addr, &len) < 0)
+    {
+    return(-1);
+    }
+
+  *port = htons(com_addr.sin_port); */
+
+  /*
+  ** Open a TCP socket (an Internet stream socket)
+  */
+  if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+    {
+    return(-1);
+    }
+
+  /*
+  ** Make sure that address may be reused
+  */
+#if defined(SUN) || (WIN32|WINNT)
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option));
+#else
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
+#endif
+
+  /*
+  ** Open connection aktiv
+  ** Let bind() select a port number
+  */
+  bzero((char *) &serv_addr, sizeof(serv_addr));
+  if(bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
+    {
+    return(-1);
+    }
+
+  /*
+  ** Get the port number bind selected
+  */
+  len = sizeof (serv_addr);
+  if(getsockname(fd, (struct sockaddr *)&serv_addr, &len) < 0)
+    {
+    return(-1);
+    }
+  *port = ntohs(serv_addr.sin_port);
+
+  listen(fd, 5);
+
+  return(fd);
+  }
+
+/*======================================================================
+ *
+ *  Read/write routines with timeout detection.
+ *
+ *  Usage: write_to(fd, buffer, n, timeout)
+ *          read_to(fd, buffer, n, timeout)
+ *
+ *  David Chavez
+ *  Engineering Services & Software
+ *  7841 New Salem Street
+ *  San Diego, CA 92126
+ *  USA
+ *
+ *  dec@essw.com
+ *
+ *====================================================================*/
+#if WIN32|WINNT
+#include <time.h>
+#else
+#include <sys/fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+
+#if !(WIN32|WINNT)
+static sigset_t newmask, oldmask, zeromask;
+#endif
+
+static int set_noblock(int fd)
+{
+#if WIN32|WINNT
+       u_long argp=1;
+
+       return ioctlsocket (fd, FIONBIO , &argp); 
+#else
+
+       sigemptyset(&zeromask);
+       sigemptyset(&newmask);
+       sigaddset(&newmask, SIGHUP);
+       sigaddset(&newmask, SIGUSR1);
+       sigaddset(&newmask, SIGUSR2);
+       if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) return -1;
+
+       return fcntl(fd, F_SETFL, O_NONBLOCK | O_NDELAY /* | FNBIO*/);
+#endif
+}
+
+int write_to(int fd, void *buffer, int n, int timeout)
+{
+       int nrem, nw;
+       char *bptr;
+       int  error;
+#if defined(SYSV) || (WIN32|WINNT)
+       int    width = 20;
+#else
+       int    width = getdtablesize();
+#endif
+       fd_set writefds;
+       struct timeval select_timeout;
+
+       select_timeout.tv_sec = timeout;
+#if WIN32|WINNT
+       select_timeout.tv_usec = 0;
+#else /* is this just a typo? */
+       select_timeout.tv_usec = 0.;
+#endif
+
+       /*  Set fd to non-blocking  */
+
+       if (set_noblock(fd) != 0) return -1;
+
+       /*  Write to fd until no more can be written  */
+
+       FD_ZERO(&writefds);
+
+       FD_SET((unsigned int)fd, &writefds);
+       for( nrem = n, bptr = buffer; nrem;)
+               {
+               if(( error = select(width, 
+                                   (fd_set *) 0, 
+                                   &writefds, 
+                                    (fd_set *) 0, 
+                           &select_timeout)) <= 0 && errno != EINTR) break;
+    
+               if(errno != EINTR && ( nw =  write(fd, bptr, nrem)) <= 0) {
+                       /*
+                        *  check for error number - and keep trying to
+                        *  write
+                        */
+                       if(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
+                               {
+                               continue;
+                               }
+                       else
+                               {
+                               error = nw;
+                               break;
+                               }
+               } else {
+                       nrem -= nw;
+                       bptr += nw;
+               }
+       }
+#if !(WIN32|WINNT)
+       if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) return -1;
+#endif
+       if( ! error ) {
+               errno = ETIMEDOUT;
+               return(-2);
+       } else if (error < 0) {
+               return(error);
+       } else {
+               return(n);
+       }
+}
+
+int read_to(int fd, char *buffer, int n, int timeout)
+  {
+  int nrem, nread, nr;
+  char *bptr;
+  int  error;
+
+#if defined(SYSV) || (WIN32|WINNT)
+  int    width = 20;
+#else
+  int    width = getdtablesize();
+#endif
+  fd_set readfds;
+  struct timeval select_timeout;
+
+  select_timeout.tv_sec = timeout;
+#if WIN32|WINNT
+  select_timeout.tv_usec = 0;
+#else
+  select_timeout.tv_usec = 0.;
+#endif
+  
+  /*  Set fd to non-blocking  */
+
+  if (set_noblock(fd) != 0) return -1;
+
+  FD_ZERO(&readfds);
+
+  FD_SET((unsigned int)fd, &readfds);
+  
+  for( nrem = n, bptr = buffer, nread = 0; nrem;)
+    {
+    if(( error = select(width, 
+            &readfds, 
+            (fd_set *) 0, 
+            (fd_set *) 0, 
+            &select_timeout)) <= 0 && errno != EINTR) break;
+    
+    if(errno != EINTR && (nr =  read (fd, bptr, nrem)) < 0)
+      {
+      /*
+       *  check for error number - and keep trying to
+       *  read
+       */
+      if(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
+        {
+        continue;
+        }
+      else
+        {
+        error = nr;
+        break;
+        }
+      }
+    else if(nr == 0)
+      {
+      break;
+      }
+    else
+      {
+      nread += nr;
+      bptr  += nr;
+      nrem  -= nr;
+      }
+    }
+
+#if !(WIN32|WINNT)
+  if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) return -1;
+#endif
+  if( ! error )
+    {
+    errno = ETIMEDOUT;
+    return(-2);
+    }
+  else if ( error < 0) 
+    {
+    return(-1);
+    }
+  else
+    {
+    return(nread);
+    }
+  }
+
+void set_swap(int do_swap)
+{
+     swap_on = do_swap;
+}
+
+/***********************************************************************
+* Function open_hg_connection()                                        *
+*                                                                      *
+***********************************************************************/
+int open_hg_connection(char *server_name, int port)
+{
+       int sockfd;
+       int option = 1;
+       struct sockaddr_in server_addr;
+       struct hostent *hp;
+       if ( (hp = gethostbyname(server_name)) == NULL )  {
+               return(-1);
+       }
+
+       bzero((char *)&server_addr, sizeof(server_addr));
+       server_addr.sin_family = AF_INET;
+       if ( port != 0 )
+               server_addr.sin_port = htons(port);
+       else
+               server_addr.sin_port = htons(HG_SERVER_PORT); 
+       bcopy(hp->h_addr, (char *) &server_addr.sin_addr, hp->h_length);
+
+       if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )  {
+               return(-2);
+       }
+
+#if defined(SUN) || (WIN32|WINNT)
+       setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option));
+#else
+       setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
+#endif /* SUN */
+
+       if (connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
+               close(sockfd);
+               return(-3);
+       } 
+
+#if !(WIN32|WINNT)
+       if ( (sock_flags = fcntl(sockfd, F_GETFL, 0)) == -1 )
+#endif
+
+       if ( set_nonblocking(sockfd) == -1 )  {
+               return(-4);
+       }
+
+       return(sockfd);
+}
+
+
+/***********************************************************************
+* Function initialize_hg_connection()                                  *
+*                                                                      *
+***********************************************************************/
+int initialize_hg_connection(int sockfd, int *do_swap, int *version, char **userdata,  char **server_string, char *username, char *password)
+{
+       char buf, c;
+        char *tmp;
+       hg_msg *ready_msg, *retmsg, msg;
+       int i = 0x01;
+       int length;
+
+       *do_swap = 0;
+       buf = 'T';
+       if ( hg_write(sockfd, &buf, 1) == -1 )  {
+               return(-2);
+       }
+
+       if ( hg_read_exact(sockfd, &buf, 1) == -1 )  {
+               return(-3);
+       }
+       if ( buf == 'F' )  {
+               return(-4);
+       }
+       if ( buf != 'T' )  {
+               return(-5);
+       }
+
+       buf = c = ( *(char *)&i )  ? 'l' : 'B';
+       if ( hg_write(sockfd, &buf, 1) == -1 )  {
+               return(-6);
+       }
+       if ( hg_read_exact(sockfd, &buf, 1) == -1 )  {
+               return(-7);
+       }
+       if ( c != buf )  {
+               swap_on = 1;
+               *do_swap = 1;
+       } else {
+               swap_on = 0;
+               *do_swap = 0;
+       }
+
+       if ( send_ready(sockfd) == -1) {
+               return(-8);
+               }
+
+       /* Receive return from Ready message */
+       if ( (ready_msg = recv_ready(sockfd)) == NULL )  {
+               return(-9);
+       }   
+
+       if ((ready_msg->version_msgid & F_VERSION) < VERSION)
+               return(-8);
+       *version = ready_msg->version_msgid;
+       *server_string = strdup(ready_msg->buf+4);
+       efree(ready_msg->buf);
+       efree(ready_msg);
+
+       /* If we have a username and password then do the identification. */
+       if((NULL != username) && (NULL != password)) {
+               length = HEADER_LENGTH + sizeof(int) + strlen(username) + 1 + strlen(password) + 1;
+
+               build_msg_header(&msg, length, msgid++, IDENTIFY_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, 0);
+               tmp = build_msg_str(tmp, username);
+               tmp = build_msg_str(tmp, password);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       return(-10);
+               }
+               efree(msg.buf);
+       }
+
+       if((NULL != username) && (NULL != password)) {
+               /* Receive return form identify message */
+               retmsg = recv_hg_msg(sockfd);
+               if ( retmsg == NULL )
+                       return(-11);
+
+               *userdata = retmsg->buf;
+               efree(retmsg);
+       }
+
+       return(0);
+}
+
+
+static int set_nonblocking(int fd)
+{
+#if WIN32|WINNT
+       unsigned int argp=0;
+
+/*     if ( sock_flags == -1 )
+               getsockopt (fd, SOL_SOCKET, optname, optval, optlen); 
+*/     if(ioctlsocket (fd, FIONBIO , &argp) == -1)
+               return(-1);
+#else
+       if ( sock_flags == -1 )
+               sock_flags = fcntl(fd, F_GETFL, 0);
+       if ( fcntl(fd, F_SETFL, O_NONBLOCK) == -1 )
+               return(-1);
+#endif
+       non_blocking = 1;
+       return(0);
+}
+
+
+static int set_blocking(int fd)
+{
+#if WIN32|WINNT
+       unsigned int argp=1;
+
+       if(ioctlsocket (fd, FIONBIO , &argp) == -1)
+               return(-1);
+#else
+       if ( fcntl(fd, F_SETFL, sock_flags) == -1 )
+               return(-1);
+#endif
+       return(0);
+}
+
+
+static int hg_read_exact(int sockfd, char *buf, int size)
+{
+       int len = 0;
+
+       len = read_to(sockfd, (void *) buf, size, rtimeout);
+       if ( len < 0 ) 
+               return -1;
+       return(0);
+}
+
+
+static int hg_read(int sockfd, char *buf, int size)
+{
+       int try = 0;
+       int len = 0;
+
+       if ( !non_blocking )
+               set_nonblocking(sockfd);  
+       while ( len == 0 )  {
+               len = recv(sockfd, (void *) buf, size, 0);
+               if ( len == -1 )  {
+                       if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) )  {
+                               if ( ++try > 5 )
+                                       return(-1);
+                               sleep(1);
+                       } 
+                       else return(-1);
+               } 
+       }
+       return(len);
+}
+
+
+static int hg_write(int sockfd, char *buf, int size)
+{
+       int try = 0;
+       int len = 0;
+
+       if ( !non_blocking )
+               set_nonblocking(sockfd);  
+       while ( size > 0 )  {
+               len = send(sockfd, (void *) buf, size, 0);
+               if ( len == -1 )  {
+                       if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) )  {
+                               if ( ++try > 5 )
+                                       return(-1);
+                               sleep(1);
+                       } 
+                       else return(-1);
+               } 
+               else  {
+                       size -= len;
+                       buf  += len;
+                       try   = 0;
+               }
+       }
+       return(0);
+}
+
+
+hg_msg *recv_hg_msg(int sockfd)
+{
+       hg_msg *msg;
+
+       if ( (msg = (hg_msg *)emalloc(sizeof(hg_msg))) == NULL )  {
+/*             php3_printf("recv_hg_msg"); */
+               lowerror = LE_MALLOC;
+               return(NULL);
+       }
+
+       if ( hg_read_exact(sockfd, (char *)&(msg->length), 4) == -1 )  {
+/*             php3_printf("recv_hg_msg: hg_read (1) returned -1\n"); */
+               efree(msg);
+               return(NULL);
+       }
+
+       if ( hg_read_exact(sockfd, (char *)&(msg->version_msgid), 4) == -1 )  {
+/*             php3_printf("recv_hg_msg: hg_read (2) returned -1\n"); */
+               efree(msg);
+               return(NULL);
+       }
+
+       if ( hg_read_exact(sockfd, (char *)&(msg->msg_type), 4) == -1 )  {
+/*             php3_printf("recv_hg_msg: hg_read (3) returned -1\n"); */
+               efree(msg);
+               return(NULL);
+       }
+
+       if ( msg->length > HEADER_LENGTH )  {
+               if ( (msg->buf = (char *) emalloc(msg->length-HEADER_LENGTH)) == NULL )  {
+/*                     php3_printf("recv_hg_msg"); */
+                       lowerror = LE_MALLOC;
+                       efree(msg);
+                       return(NULL);
+               }
+               if ( hg_read_exact(sockfd, msg->buf, msg->length-HEADER_LENGTH) == -1 )  {
+/*                     php3_printf("recv_hg_msg: hg_read (4) returned -1\n"); */
+                       efree(msg->buf);
+                       efree(msg);
+                       return(NULL);
+               }
+       }
+       else
+               msg->buf = NULL;  
+
+#ifdef HW_DEBUG
+       php3_printf("<B>   Recv msg: </B>type = %d -- id = %d<BR>\n", msg->msg_type, msg->version_msgid);
+#endif
+       return(msg);
+}
+
+
+hg_msg *recv_ready(int sockfd)
+{
+       hg_msg *ready_msg;
+
+       if ( (ready_msg = recv_hg_msg(sockfd)) == NULL )  {
+/*             php3_printf("recv_ready: recv_hg_msg returned NULL\n"); */
+               return(NULL);
+       }    
+       if ( ready_msg->msg_type != READY_MESSAGE )  {
+/*             php3_printf("recv_ready: recv_hg_msg returned wrong message: %d, %d  \n", ready_msg->length, ready_msg->msg_type); */
+               efree(ready_msg);
+               return(NULL);
+       }
+
+       return(ready_msg);
+}
+
+
+hg_msg *recv_command(int sockfd)
+{
+       hg_msg *comm_msg;
+
+       if ( (comm_msg = recv_hg_msg(sockfd)) == NULL )  {
+/*             fprintf(stderr, "recv_command: recv_hg_msg returned NULL\n"); */
+               return(NULL);
+       }
+       if ( comm_msg->msg_type != COMMAND_MESSAGE )  {
+/*             fprintf(stderr, "recv_command: recv_hg_msg returned wrong message\n"); */
+               return(NULL);
+       }
+
+       return(comm_msg);
+}
+
+int send_dummy(int sockfd, hw_objectID objectID, int msgid, char **attributes)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, msgid);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               *attributes = NULL;
+               return(-1);
+       }
+
+       if(0 == (int) *(retmsg->buf)) {
+               *attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg->buf);
+               efree(retmsg);
+       } else {
+               error = *((int *) retmsg->buf);
+               *attributes = NULL;
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+static int bh_send_deleteobject(int sockfd, hw_objectID objectID) {
+       hg_msg msg;
+       int  length;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, DELETEOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       return(msgid-1);
+}
+
+static int uh_send_deleteobject(int sockfd) {
+       hg_msg *retmsg;
+       int  error;
+
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       if(NULL == retmsg->buf) {
+               efree(retmsg);
+               return -1;
+       }
+       error = *((int *) retmsg->buf);
+       efree(retmsg->buf);
+       efree(retmsg);
+       return(error);
+}
+
+int send_deleteobject(int sockfd, hw_objectID objectID)
+{
+       if(0 > bh_send_deleteobject(sockfd, objectID))
+               return -1;
+       return(uh_send_deleteobject(sockfd));
+}
+
+static int bh_send_changeobject(int sockfd, hw_objectID objectID, char *mod) {
+       hg_msg msg;
+       int  length;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID) + strlen(mod) + 1;
+
+       build_msg_header(&msg, length, msgid++, CHANGEOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_str(tmp, mod);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       return(msgid-1);
+}
+
+static int uh_send_changeobject(int sockfd) {
+       hg_msg *retmsg;
+       int  error;
+
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       error = *((int *) retmsg->buf);
+       return(error);
+}
+
+int send_changeobject(int sockfd, hw_objectID objectID, char *modification)
+{
+       if(0 > bh_send_changeobject(sockfd, objectID, modification))
+               return -1;
+       return(uh_send_changeobject(sockfd));
+}
+
+static int bh_send_getobject(int sockfd, hw_objectID objectID) {
+       hg_msg msg;
+       int  length;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       return(msgid-1);
+}
+
+static int uh_send_getobject(int sockfd, char **attributes) {
+       hg_msg *retmsg;
+       int  error;
+
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               *attributes = NULL;
+               return(-1);
+       }
+
+       if(0 == (int) *(retmsg->buf)) {
+               *attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg->buf);
+               efree(retmsg);
+       } else {
+               error = *((int *) retmsg->buf);
+               *attributes = NULL;
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+int send_getobject(int sockfd, hw_objectID objectID, char **attributes)
+{
+       if(0 > bh_send_getobject(sockfd, objectID))
+               return -1;
+       return(uh_send_getobject(sockfd, attributes));
+}
+
+int send_getandlock(int sockfd, hw_objectID objectID, char **attributes)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETANDLOCK_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               *attributes = NULL;
+               return(-1);
+       }
+
+       if(0 == (error = (int) *(retmsg->buf))) {
+               *attributes = estrdup(retmsg->buf+sizeof(int));
+       } else {
+               *attributes = NULL;
+       }
+
+       efree(retmsg->buf);
+       efree(retmsg);
+       return error;
+}
+
+int send_insertobject(int sockfd, char *objrec, char *parms, hw_objectID *objectID)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr;
+
+       length = HEADER_LENGTH + strlen(objrec) + 1 + strlen(parms) + 1;
+
+       build_msg_header(&msg, length, msgid++, INSERTOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, objrec);
+       tmp = build_msg_str(tmp, parms);
+/*fprintf(stderr,"objrec = %s, parms = %s\n", objrec, parms); */
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               *objectID = 0;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(0 == (error = *ptr)) {
+               ptr++;
+               *objectID = *ptr;
+       } else {
+               *objectID = 0;
+       }
+       efree(retmsg->buf);
+       efree(retmsg);
+       return error;
+}
+
+int send_unlock(int sockfd, hw_objectID objectID)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, UNLOCK_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       error = (int) *(retmsg->buf);
+
+       efree(retmsg->buf);
+       efree(retmsg);
+       return error;
+}
+
+int send_incollections(int sockfd, int retcol, int cobjids, hw_objectID *objectIDs, int ccollids, hw_objectID *collIDs, int *count, hw_objectID **retIDs)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, *ptr1, i;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID) + (cobjids + ccollids) * sizeof(hw_objectID) + 2 * sizeof(int);
+
+       build_msg_header(&msg, length, msgid++, INCOLLECTIONS_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-3);
+       }
+
+       tmp = build_msg_int(msg.buf, retcol);
+       tmp = build_msg_int(tmp, cobjids);
+       for(i=0; i<cobjids; i++)
+               tmp = build_msg_int(tmp, objectIDs[i]);
+       tmp = build_msg_int(tmp, ccollids);
+       for(i=0; i<ccollids; i++)
+               tmp = build_msg_int(tmp, collIDs[i]);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-2);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr;
+               ptr++;
+               if(NULL != (*retIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *retIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               if(retmsg->buf) efree(retmsg->buf);
+               if(retmsg) efree(retmsg);
+               return error;
+       }
+       return(0);
+}
+
+
+int send_inscoll(int sockfd, hw_objectID objectID, char *objrec, hw_objectID *new_objectID)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID) + strlen(objrec) + 1;
+
+       build_msg_header(&msg, length, msgid++, INSCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-3);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_str(tmp, objrec);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-2);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(0 != (error = *ptr)) {
+               efree(retmsg->buf);
+               efree(retmsg);
+               *new_objectID = 0;
+               return error;
+       }
+
+       ptr++;
+       *new_objectID = *ptr;
+       return 0;
+}
+
+int send_insdoc(int sockfd, hw_objectID objectID, char *objrec, char *text, hw_objectID *new_objectID)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID) + strlen(objrec) + 1;
+       if(text) {
+               length += strlen(text);
+               length++;
+       }
+
+       build_msg_header(&msg, length, msgid++, INSDOC_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-3);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_str(tmp, objrec);
+       if(text)
+               tmp = build_msg_str(tmp, text);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-2);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(0 != (error = *ptr)) {
+               efree(retmsg->buf);
+               efree(retmsg);
+               *new_objectID = 0;
+               return error;
+       }
+
+       ptr++;
+       *new_objectID = *ptr;
+       return 0;
+}
+
+int send_getdestforanchorsobj(int sockfd, char **anchorrec, char ***destrec, int count);
+int send_getreldestforanchorsobj(int sockfd, char **anchorrec, char ***reldestrec, int count, int rootID, int thisID);
+
+int send_gettext(int sockfd, hw_objectID objectID, int mode, int rootid, char **objattr, char **bodytag, char **text, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, *ptr, ancount, error;
+       char *tmp, *attributes, *documenttype;
+       char **anchors;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               attributes = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 0) {
+               attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg);
+               efree(retmsg->buf);
+       } else {
+               error = *ptr;
+               attributes = NULL;
+               efree(retmsg);
+               efree(retmsg->buf);
+               return error;
+       }
+
+       length = HEADER_LENGTH + strlen(attributes) + 1;
+       build_msg_header(&msg, length, msgid++, GETTEXT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, attributes);
+
+       documenttype = fnAttributeValue(attributes, "DocumentType");
+       *objattr = strdup(attributes);
+       efree(attributes);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if (retmsg == NULL) {
+               *text = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 0) {
+               ptr++;
+               *count = retmsg->length-HEADER_LENGTH-sizeof(int);
+               if(NULL != (*text = malloc(*count + 1))) {
+                       memcpy(*text, retmsg->buf+sizeof(int), *count);
+/*                     *text[*count] = 0; */
+               } else {
+                       efree(retmsg);
+                       efree(retmsg->buf);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *ptr;
+               efree(retmsg);
+               efree(retmsg->buf);
+               *text = NULL;
+               return(error);
+       }
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       if((documenttype != NULL) && (strcmp(documenttype, "Image") != 0)) {
+               if(send_getanchorsobj(sockfd, objectID, &anchors, &ancount) == 0) {
+                       char **destrec, **reldestrec;
+                       DLIST *pAnchorList;
+
+                       send_getdestforanchorsobj(sockfd, anchors, &destrec, ancount);
+                       send_getreldestforanchorsobj(sockfd, anchors, &reldestrec, ancount, rootid, objectID);
+                       pAnchorList = fnCreateAnchorList(anchors, destrec, reldestrec, ancount, mode);
+                       /* Free only the array, the objrecs has been freed in fnCreateAnchorList() */
+                       if(anchors) efree(anchors);
+                       if(destrec) efree(destrec);
+                       if(reldestrec) efree(reldestrec);
+
+                       if(pAnchorList != NULL) {
+                               char *newtext;
+                               char *body;
+
+                               newtext = fnInsAnchorsIntoText(*text, pAnchorList, &body);
+                               dlst_kill(pAnchorList, fnDeleteAnchor);
+                               *bodytag = strdup(body);
+                               efree(body);
+                               *text = newtext;
+                               *count = strlen(newtext);
+                       }
+               }
+       }
+
+       if(documenttype) efree(documenttype);
+       return(0);
+}
+
+int send_edittext(int sockfd, char *objattr, char *text)
+{
+       hg_msg msg, *retmsg;
+       int  length, *ptr, error;
+       char *tmp, *path, *objid;
+       hw_objectID objectID; 
+
+       objid = fnAttributeValue(objattr, "ObjectID=");
+       if(objid == NULL)
+               return(-1);
+       if(!sscanf(objid, "0x%x", &objectID))
+               return(-1);
+
+       path = fnAttributeValue(objattr, "Path=");
+       if(path == NULL)
+               return(-1);
+       length = HEADER_LENGTH + sizeof(hw_objectID) + strlen(path) + 1 + 1 + strlen(text) + 1;
+
+       build_msg_header(&msg, length, msgid++, EDITTEXT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_str(tmp, path);
+       tmp = build_msg_str(tmp, "");
+       tmp = build_msg_str(tmp, text);
+
+       if(path) efree(path);
+       if(objid) efree(objid);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if (retmsg == NULL) {
+               *text = '\0';
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       error = *ptr;
+       efree(retmsg);
+       efree(retmsg->buf);
+       return(error);
+}
+
+int send_getcgi(int sockfd, hw_objectID objectID, char *cgi_env_str, char **objattr, char **text, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, *ptr, error, new_attr_len;
+       char *tmp, *attributes, *new_attr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               attributes = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 0) {
+               attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg);
+               efree(retmsg->buf);
+       } else {
+               error = *ptr;
+               attributes = NULL;
+               efree(retmsg);
+               efree(retmsg->buf);
+               return error;
+       }
+
+        new_attr_len = strlen(attributes) + strlen(cgi_env_str) + 2;
+        new_attr = malloc(new_attr_len);
+        strcpy(new_attr, attributes);
+        strcat(new_attr, cgi_env_str);
+       length = HEADER_LENGTH + strlen(new_attr) + 1 + sizeof(int);
+       build_msg_header(&msg, length, msgid++, GETCGI_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, new_attr);
+       tmp = build_msg_int(tmp, 0);
+
+       *objattr = strdup(attributes);
+       efree(attributes);
+        free(new_attr);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if (retmsg == NULL) {
+               *text = NULL;
+               return(-1);
+       }
+
+       /* Attention: It looks like the documentation is not quite right.
+          According to the docs the buffer starts with an integer which
+          is followed by the output of the cgi script. This seems not to
+          be true. There is another integer right after the error.
+          The output of the cgi script is also preceded by the 'Content-type'
+          header. */
+       ptr = (int *) retmsg->buf;
+       if(*ptr++ == 1024) {
+               *count = *ptr++;
+               if(NULL != (*text = malloc(*count + 1))) {
+                       memcpy(*text, ptr, *count);
+               } else {
+                       efree(retmsg);
+                       efree(retmsg->buf);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *ptr + 1024;  /* move errors to >2024 */
+               efree(retmsg);
+               efree(retmsg->buf);
+               *text = NULL;
+               return(error);
+       }
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       return(0);
+}
+
+int send_getremote(int sockfd, hw_objectID objectID, char **objattr, char **text, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, *ptr, error;
+       char *tmp, *attributes;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               attributes = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 0) {
+               attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg);
+               efree(retmsg->buf);
+       } else {
+               error = *ptr;
+               attributes = NULL;
+               efree(retmsg);
+               efree(retmsg->buf);
+               return error;
+       }
+
+       length = HEADER_LENGTH + strlen(attributes) + 1 + sizeof(int);
+       build_msg_header(&msg, length, msgid++, GETREMOTE_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, attributes);
+       tmp = build_msg_int(tmp, 0);
+
+       *objattr = strdup(attributes);
+       efree(attributes);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if (retmsg == NULL) {
+               *text = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 1024) {
+               *count = retmsg->length-HEADER_LENGTH-sizeof(int)-sizeof(int);
+               if(NULL != (*text = malloc(*count + 1))) {
+                       memcpy(*text, ptr+2, *count);
+/*                     *text[*count] = 0; */
+               } else {
+                       efree(retmsg);
+                       efree(retmsg->buf);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *ptr + 1024;  /* move errors to >2024 */
+               efree(retmsg);
+               efree(retmsg->buf);
+               *text = NULL;
+               return(error);
+       }
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       return(0);
+}
+
+int send_getremotechildren(int sockfd, char *attributes, char **text, int **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, *ptr, *ptr1, error;
+       char *tmp;
+
+/*     length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if(retmsg == NULL) {
+               attributes = NULL;
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(*ptr == 0) {
+               attributes = estrdup(retmsg->buf+sizeof(int));
+               efree(retmsg);
+               efree(retmsg->buf);
+       } else {
+               error = *ptr;
+               attributes = NULL;
+               efree(retmsg);
+               efree(retmsg->buf);
+               return error;
+       }
+*/
+       length = HEADER_LENGTH + strlen(attributes) + 1 + sizeof(int);
+       build_msg_header(&msg, length, msgid++, GETREMOTECHILDREN_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, attributes);
+       tmp = build_msg_int(tmp, 0);
+
+/*     efree(attributes); */ 
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if (retmsg == NULL) {
+               *childIDs = NULL;
+               return(-1);
+       }
+       ptr = (int *) retmsg->buf;
+       if(*ptr++ == 1024) {
+               int i, remlen, sum;
+               *count = *ptr;
+               ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       sum = 0;
+                       for(i=0; i<*count; ptr++, i++) {
+                               ptr1[i] = *ptr;
+                               sum += *ptr;
+                       }
+               } else {
+                       efree(retmsg);
+                       efree(retmsg->buf);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               remlen = retmsg->length - HEADER_LENGTH - *count * sizeof(int) - 2 * sizeof(int);
+/*ptr1[i-1] = remlen; */
+/*ptr1[i-2] = sum; */
+/*ptr1[i-3] = *count; */
+               if(NULL != (*text = emalloc(remlen + 1))) {
+                       memcpy(*text, ptr, remlen);
+               } else {
+                       efree(childIDs);
+                       efree(retmsg);
+                       efree(retmsg->buf);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+               efree(retmsg->buf);
+               efree(retmsg);
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               *childIDs = NULL;
+               *text = NULL;
+               return error;
+       }
+       return(0);
+}
+
+int send_mvcpdocscollscoll(int sockfd, hw_objectID *objectIDs, int count, int from, int dest, int cpmv, int doccoll)
+{
+       hg_msg msg, *retmsg;
+       int  length, i, error;
+       char *tmp;
+
+       if(count <= 0)
+               return 0;
+
+       /*       HEADER_LENGTH + cpmv                + from                + dest                + count + nr of obj */
+       length = HEADER_LENGTH + sizeof(hw_objectID) + sizeof(hw_objectID) + sizeof(hw_objectID) + sizeof(hw_objectID) + count * sizeof(hw_objectID);
+
+       switch(doccoll) {
+               case DOCUMENT:
+                       build_msg_header(&msg, length, msgid++, MVCPDOCSCOLL_MESSAGE);
+                       break;
+               case COLLECTION:
+                       build_msg_header(&msg, length, msgid++, MVCPCOLLSCOLL_MESSAGE);
+                       break;
+       }
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, cpmv);
+       tmp = build_msg_int(tmp, from);
+       tmp = build_msg_int(tmp, dest);
+       tmp = build_msg_int(tmp, count);
+       for(i=0; i<count;i++)
+               tmp = build_msg_int(tmp,objectIDs[i]);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       efree(retmsg);
+       error = *((int *) retmsg->buf);
+       efree(retmsg->buf);
+       return(error);
+}
+
+int send_docbyanchor(int sockfd, hw_objectID objectID, hw_objectID *anchorID)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETDOCBYANCHOR_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       error = *ptr++;
+       if(error == 0) {
+               *anchorID = *ptr;
+       } else {
+               *anchorID = 0;
+       }
+       efree(retmsg->buf);
+       efree(retmsg);
+       return error;
+}
+
+int send_docbyanchorobj(int sockfd, hw_objectID objectID, char **objrec)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, anchorID;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETDOCBYANCHOR_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       error = *ptr++;
+       if(error == 0) {
+               anchorID = *ptr;
+       } else {
+               anchorID = 0;
+       }
+       efree(retmsg->buf);
+       efree(retmsg);
+
+       if(0 > bh_send_getobject(sockfd, anchorID))
+               return -1;
+       return(uh_send_getobject(sockfd, objrec));
+}
+
+int send_children(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       int *ptr, *ptr1;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, CHILDREN_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if (-1 == send_hg_msg(sockfd, &msg, length))  {
+               efree(msg.buf);
+               return(-2);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-3);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+int send_childrenobj(int sockfd, hw_objectID objectID, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, i, error;
+       char *tmp, **objptr;
+       int *childIDs = NULL;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, CHILDREN_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       for(i=0; i<*count; ptr++, i++)
+                               childIDs[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each child collection the object record */
+       for(i=0; i<*count; i++) {
+               
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+                       efree(childIDs);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(childIDs);
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       efree(childIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+       *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getchildcoll(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, i, *ptr1;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETCHILDCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+int send_getchildcollobj(int sockfd, hw_objectID objectID, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, i, error;
+       char *tmp, **objptr;
+       int *childIDs = NULL;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETCHILDCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       for(i=0; i<*count; ptr++, i++)
+                               childIDs[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each child collection the object record */
+       for(i=0; i<*count; i++) {
+               
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+                       efree(childIDs);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(childIDs);
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       efree(childIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+       *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getchilddoccoll(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETCHILDDOCCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } else {
+               efree(msg.buf);
+               retmsg = recv_hg_msg(sockfd);
+               if ( retmsg != NULL )  {
+                       int *ptr, i, *ptr1;
+
+                       ptr = (int *) retmsg->buf;
+                       if(ptr == NULL) {
+                               if(retmsg) efree(retmsg);
+                               return -1;
+                       }
+                       if(*ptr++ == 0) {
+                               *count = *ptr++;
+                               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                                       ptr1 = *childIDs;
+                                       for(i=0; i<*count; ptr++, i++)
+                                               ptr1[i] = *ptr;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                                       lowerror = LE_MALLOC;
+                                       return(-1);
+                               }
+                       } else {
+                               error = *((int *) retmsg->buf);
+                               efree(retmsg->buf);
+                               efree(retmsg);
+                               return error;
+                       }
+               }
+       }
+
+       return(0);
+
+}
+
+int send_getchilddoccollobj(int sockfd, hw_objectID objectID, hw_objrec ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, i, error;
+       char *tmp, **objptr;
+       int *childIDs = NULL;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETCHILDDOCCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg != NULL )  {
+               int *ptr, i;
+
+               ptr = (int *) retmsg->buf;
+               if(ptr == NULL) {
+                       if(retmsg->buf) efree(retmsg->buf);
+                       return -1;
+               }
+               if(*ptr++ == 0) {
+                       *count = *ptr++;
+                       if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                               for(i=0; i<*count; ptr++, i++)
+                                       childIDs[i] = *ptr;
+                               efree(retmsg->buf);
+                               efree(retmsg);
+                       } else {
+                               efree(retmsg->buf);
+                               efree(retmsg);
+                               lowerror = LE_MALLOC;
+                               return(-1);
+                       }
+               } else {
+                       error = *((int *) retmsg->buf);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       return error;
+               }
+       }
+
+       /* Now get for each child collection the object record */
+       for(i=0; i<*count; i++) {
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+       *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getanchors(int sockfd, hw_objectID objectID, int **anchorIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, i, *ptr1;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETANCHORS_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       if (NULL == (retmsg = recv_hg_msg(sockfd)))
+          return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (*anchorIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *anchorIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+int send_getanchorsobj(int sockfd, hw_objectID objectID, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, i, *ptr1;
+       int *anchorIDs = NULL;
+       char **objptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, 50, GETANCHORS_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       if (NULL == (retmsg = recv_hg_msg(sockfd)))
+          return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (anchorIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = anchorIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each anchor the object record */
+       for(i=0; i<*count; i++) {
+               
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, anchorIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, anchorIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       if(anchorIDs) efree(anchorIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+       *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getdestforanchorsobj(int sockfd, char **anchorrec, char ***destrec, int count)
+{
+       int i;
+       char *objptr, **destptr;
+       char *str;
+       int objectID;
+
+       if(NULL == (destptr = (char **) emalloc(count * sizeof(hw_objrec *)))) {
+               lowerror = LE_MALLOC;
+               return -1;
+               }
+
+       /* Now get for each anchor the object record of its destination */
+       for(i=0; i<count; i++) {
+               /* if you retrieve the anchors you sometimes get more than actually accessible.
+                  This happens for the object 0x29a9c. */
+               if((NULL != anchorrec[i]) && (NULL != (str = fnAttributeValue(anchorrec[i], "Dest")))) {
+                       sscanf(str, "0x%x", &objectID);
+                       efree(str);
+
+                       if(0 > send_docbyanchorobj(sockfd, objectID, &objptr)) {
+                               efree(destptr);
+                               return -1;
+                       }
+                       destptr[i] = objptr;
+                       /* if we can't get the object rec of the dest, than this document
+                          is probably not accessible for us. For later functions simply
+                          set anchorrec[i] to NULL */
+                       if(destptr[i] == NULL) {
+                               if(anchorrec[i]) efree(anchorrec[i]);
+                               anchorrec[i] = NULL;
+                       }
+               } else {
+                       destptr[i] = NULL;
+               }
+       }
+       *destrec = destptr;
+
+       return(0);
+}
+
+int send_getreldestforanchorsobj(int sockfd, char **anchorrec, char ***reldestrec, int count, int rootID, int thisID)
+{
+       int i;
+       char *docofanchorptr, **reldestptr;
+       char *str;
+       int destobjectID;
+
+       if(NULL == (reldestptr = (char **) emalloc(count * sizeof(char *)))) {
+               lowerror = LE_MALLOC;
+               return -1;
+               }
+
+       /* Now get for each anchor the object record of its destination */
+       for(i=0; i<count; i++) {
+               /* if you retrieve the anchors you sometimes get more than actually accessible.
+               */
+               if((NULL != anchorrec[i]) && (NULL != (str = fnAttributeValue(anchorrec[i], "Dest")))) {
+                       sscanf(str, "0x%x", &destobjectID);
+                       efree(str);
+
+                       if(0 > send_docbyanchorobj(sockfd, destobjectID, &docofanchorptr)) {
+                               efree(reldestptr);
+                               return -1;
+                       }
+                       reldestptr[i] = docofanchorptr;
+                       /* if we can't get the object rec of the dest, than this document
+                          is probably not accessible for us. For later functions simply
+                          set anchorrec[i] to NULL */
+                       if(reldestptr[i] == NULL) {
+                               if(anchorrec[i]) efree(anchorrec[i]);
+                               anchorrec[i] = NULL;
+                       } else {
+                               int j, k, *retthisIDs, *retdestIDs, equaltill, mincount, countthis, countdest, destdocid;
+                               char destdocname[200];
+                               char anchorstr[300];
+                               char temp[200];
+                               char *strptr;
+
+                               if(NULL != (str = strstr(docofanchorptr, "Name="))) {
+                                       str += 5;
+                                       sscanf(str, "%s\n", destdocname);
+                               }
+                               if(NULL != (str = strstr(docofanchorptr, "ObjectID="))) {
+                                       str += 9;
+                                       sscanf(str, "0x%X", &destdocid);
+                               }
+                               
+                               send_incollections(sockfd, 1, 1, &thisID, 1, &rootID, &countthis, &retthisIDs);
+                               send_incollections(sockfd, 1, 1, &destdocid, 1, &rootID, &countdest, &retdestIDs);
+
+fprintf(stderr, "%d: ", thisID);
+for(k=0; k<countthis; k++)
+       fprintf(stderr,"%d, ", retthisIDs[k]);
+fprintf(stderr,"\n");
+fprintf(stderr,"%d: ", destdocid);
+for(k=0; k<countdest; k++)
+       fprintf(stderr,"%d: %d, ", destdocid, retdestIDs[k]);
+fprintf(stderr,"\n");
+
+                               mincount = (countthis < countdest) ? countthis : countdest;
+                               for(j=0; (j<mincount) && (retthisIDs[j]==retdestIDs[j]); j++)
+                                       ;
+                               equaltill = j;
+                               strcpy(anchorstr, "Name=");
+                               for(j=equaltill; j<countthis; j++)
+                                       strcat(anchorstr, "../");
+                               strcat(anchorstr, "./");
+                               for(j=equaltill; j<countdest; j++) {
+                                       char *temprec, tempname[100], objectidstr[100];
+                                       send_getobject(sockfd, retdestIDs[j], &temprec);
+                                       if(NULL != (str = strstr(temprec, "Name="))) {
+                                               str += 5;
+                                               sscanf(str, "%s\n", tempname);
+                                       } else if(NULL != (str = strstr(temprec, "ObjectID="))) {
+                                               str += 9;
+                                               sscanf(str, "%s\n", tempname);
+                                       }
+
+                                       sprintf(temp, "%s", tempname);
+                                       strptr = temp;
+                                       while(*strptr != '\0') {
+                                               if(*strptr == '/')
+                                                       *strptr = '_';
+                                               strptr++;
+                                       }
+fprintf(stderr, "Adding '%s' to '%s'\n", temp, anchorstr);
+                                       strcat(anchorstr, temp);
+                                       strcat(anchorstr, "/");
+fprintf(stderr, "Is now '%s'\n", anchorstr);
+                                       efree(temprec);
+                               }
+                               /* if the anchor destination is a collection it may not be added anymore. */
+                               if(destdocid != retdestIDs[countdest-1]) {
+                                       strptr = destdocname;
+                                       while(*strptr != '\0') {
+                                               if(*strptr == '/')
+                                                       *strptr = '_';
+                                               strptr++;
+                                       }
+                                       strcat(anchorstr, destdocname);
+                               } else {
+                                       strcat(anchorstr, "index.html");
+                               }
+                               strcat(anchorstr, "\n");
+                               sprintf(temp, "ObjectID=0x%x", destdocid);
+                               strcat(anchorstr, temp);
+fprintf(stderr, "%s\n", anchorstr);
+                               efree(retthisIDs);
+                               efree(retdestIDs);
+                               reldestptr[i] = estrdup(anchorstr);
+                       }
+               } else {
+                       reldestptr[i] = NULL;
+               }
+       }
+       *reldestrec = reldestptr;
+
+       return(0);
+}
+
+int fn_findpath(int sockfd, int *retIDs, int count, int id) {
+       int *pathIDs;
+       int *parentIDs, pcount, pid;
+       int u, j, i;
+       
+       if(NULL == (pathIDs = emalloc(count * sizeof(int)))) {
+               lowerror = LE_MALLOC;
+               return -1;
+       }
+       u = count-1;
+       pid = id;
+       pcount = 1;
+       /* FIXME but parentIDs is not set at this point, why checking it? */
+       while((u >= 0) && (pcount != 0) && (parentIDs != NULL) && (pid != 0)) {
+/*fprintf(stderr, "Get parents for %d\n", pid); */
+               if(0 != send_getparents(sockfd, pid, &parentIDs, &pcount)) {
+                       efree(pathIDs);
+                       return -1;
+               }
+               pid = 0;
+               for(i=0; i<pcount; i++) {
+                       for(j=0; j<count; j++) {
+                               if(parentIDs[i] == retIDs[j]) {
+                                       pathIDs[u--] = retIDs[j];
+                                       pid = retIDs[j];
+                               }
+                       }
+               }
+               if(pid == 0)
+                       fprintf(stderr, "parent not found in list\n");
+               if(parentIDs) efree(parentIDs);
+       }
+/*fprintf(stderr, "sorted path: "); */
+       for(i=0; i<count; i++) {
+               retIDs[i] = pathIDs[i];
+/*fprintf(stderr, "%d, ", retIDs[i]); */
+       }
+/*fprintf(stderr, "\n"); */
+       efree(pathIDs);
+       return 0;
+}
+
+/********************************************************************
+* function getrellink()                                             *
+*                                                                   *
+* Returns the link to point from document with ID sourceID to       *
+* document with id destID.                                          *
+********************************************************************/
+int getrellink(int sockfd, int rootID, int thisID, int destID, char **reldeststr) {
+       int i, j, k, *retthisIDs, *retdestIDs, equaltill, count, mincount, countthis, countdest, destdocid;
+       char anchorstr[300];
+       char temp[200];
+       char *strptr;
+
+       send_incollections(sockfd, 1, 1, &thisID, 1, &rootID, &countthis, &retthisIDs);
+       send_incollections(sockfd, 1, 1, &destID, 1, &rootID, &countdest, &retdestIDs);
+
+
+fprintf(stderr, "%d: ", thisID);
+for(k=0; k<countthis; k++)
+       fprintf(stderr,"%d, ", retthisIDs[k]);
+fprintf(stderr,"\n");
+fprintf(stderr,"%d: ", destID);
+for(k=0; k<countdest; k++)
+       fprintf(stderr,"%d, ", retdestIDs[k]);
+fprintf(stderr,"\n");
+
+       /*
+       ** The message incollections returned a list of collections
+       ** in which the destID or thisID is contained. Unfortunately
+       ** this list ist not the path for the destID or thisID, but
+       ** a sorted list of collection IDs. If for example you are
+       ** looking for an ID 20 which has a path 1 -> 5 -> 4 -> 20
+       ** (this means: 20 is child of 4, 4 is child of 5, 5 is child
+       ** of 1) it will return 1,4,5 instead of 1,5,4
+       ** Consequently, we have to create the correct path, by checking
+       ** for the parents and identifying it in the list.
+       ** But there is another problem. If the id for which the list of
+       ** of collection is generated is a colletion itself, it will
+       ** show up in the list as well. In order to make the algorithmn
+       ** work proberly it has to be the last member of the list.
+       */
+       for(i=0; i<countdest; i++)
+               if(retdestIDs[i] == destID) {
+                       retdestIDs[i] = retdestIDs[countdest-1];
+                       retdestIDs[countdest-1] = destID;
+               }
+       count = (retdestIDs[countdest-1] == destID) ? countdest-1 : countdest;
+       if(0 != fn_findpath(sockfd, retdestIDs, count, destID)) {
+               efree(retthisIDs);
+               efree(retdestIDs);
+               return -1;
+       }
+       for(i=0; i<countthis; i++)
+               if(retthisIDs[i] == thisID) {
+                       retthisIDs[i] = retthisIDs[countthis-1];
+                       retthisIDs[countthis-1] = thisID;
+               }
+       count = (retthisIDs[countthis-1] == thisID) ? countthis-1 : countthis;
+       if(0 != fn_findpath(sockfd, retthisIDs, count, thisID)) {
+               efree(retthisIDs);
+               efree(retdestIDs);
+               return -1;
+       }
+
+       mincount = (countthis < countdest) ? countthis : countdest;
+fprintf(stderr,"mincount = %d\n", mincount);
+       for(j=0; (j<mincount) && (retthisIDs[j]==retdestIDs[j]); j++)
+               ;
+       equaltill = j;
+fprintf(stderr, "first unequal = %d\n", j);
+       strcpy(anchorstr, "");
+       for(j=equaltill; j<countthis; j++)
+               strcat(anchorstr, "../");
+       strcat(anchorstr, "./");
+       for(j=equaltill; j<countdest; j++) {
+               char *temprec, *str, tempname[100], objectidstr[100];
+               if(0 == send_getobject(sockfd, retdestIDs[j], &temprec)) {
+                       if(NULL != (str = strstr(temprec, "Name="))) {
+                               str += 5;
+                               sscanf(str, "%s\n", tempname);
+                       } else if(NULL != (str = strstr(temprec, "ObjectID="))) {
+                               str += 9;
+                               sscanf(str, "%s\n", tempname);
+                       }
+       
+                       sprintf(temp, "%s", tempname);
+                       strptr = temp;
+                       while(*strptr != '\0') {
+                               if(*strptr == '/')
+                                       *strptr = '_';
+                               strptr++;
+                       }
+fprintf(stderr, "Adding '%s' (%d) to '%s'\n", temp, retdestIDs[j], anchorstr);
+                       strcat(anchorstr, temp);
+                       strcat(anchorstr, "/");
+fprintf(stderr, "Is now '%s'\n", anchorstr);
+                       efree(temprec);
+               } else {
+                       strcat(anchorstr, "No access/");
+               }
+       }
+       /* if the anchor destination is a collection it may not be added anymore. */
+       if(destID != retdestIDs[countdest-1]) {
+               char destdocname[100], *str;
+               send_getobject(sockfd, destID, &str);
+               if(NULL != (strptr = strstr(str, "Name="))) {
+                       strptr += 5;
+                       sscanf(strptr, "%s\n", destdocname);
+               }
+               strptr = destdocname;
+               while(*strptr != '\0') {
+                       if(*strptr == '/')
+                               *strptr = '_';
+                       strptr++;
+               }
+               strcat(anchorstr, destdocname);
+               efree(str);
+       } else {
+/*             strcat(anchorstr, "index.html"); */
+       }
+/*fprintf(stderr, "%s\n", anchorstr); */
+       efree(retthisIDs);
+       efree(retdestIDs);
+       *reldeststr = estrdup(anchorstr);
+       return 0;
+}
+
+int send_identify(int sockfd, char *name, char *passwd, char **userdata) {
+       hg_msg msg, *retmsg;
+       int  length;
+       char *tmp;
+
+       length = HEADER_LENGTH + sizeof(int) + strlen(name) + 1 + strlen(passwd) + 1;
+
+       build_msg_header(&msg, length, msgid++, IDENTIFY_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, 0);
+       tmp = build_msg_str(tmp, name);
+       tmp = build_msg_str(tmp, passwd);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )
+               return(-1);
+
+       *userdata = (char *) retmsg->buf;
+       efree(retmsg);
+
+       return(0);
+}
+
+int send_getobjbyquery(int sockfd, char *query, int maxhits, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, i, *ptr1;
+
+       length = HEADER_LENGTH + strlen(query) + 1;
+
+       build_msg_header(&msg, length, msgid++, GETOBJBYQUERY_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, query);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) 
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = (*ptr < maxhits) ? *ptr : maxhits;
+               ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+       return(0);
+}
+
+int send_getobjbyqueryobj(int sockfd, char *query, int maxhits, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       int *childIDs = NULL;
+       char **objptr;
+       int *ptr, *ptr1;
+
+       length = HEADER_LENGTH + strlen(query) + 1;
+
+       build_msg_header(&msg, length, msgid++, GETOBJBYQUERY_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, query);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) 
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = (*ptr < maxhits) ? *ptr : maxhits;
+               ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each child collection the object record */
+       for(i=0; i<*count; i++) {
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       efree(childIDs);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       efree(childIDs);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       efree(childIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+               *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getobjbyquerycoll(int sockfd, hw_objectID collID, char *query, int maxhits, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int  length, error;
+       char *tmp;
+       int *ptr, i, *ptr1;
+
+       length = HEADER_LENGTH + strlen(query) + 1 + sizeof(int) + sizeof(collID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJBYQUERYCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, 1);
+       tmp = build_msg_int(tmp, collID);
+       tmp = build_msg_str(tmp, query);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) 
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = (*ptr < maxhits) ? *ptr : maxhits;
+               ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+       return(0);
+}
+
+int send_getobjbyquerycollobj(int sockfd, hw_objectID collID, char *query, int maxhits, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       hw_objectID *childIDs = NULL;
+       char **objptr;
+       int *ptr, *ptr1;
+
+       length = HEADER_LENGTH + strlen(query) + 1 + sizeof(int) + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETOBJBYQUERYCOLL_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, 1);
+       tmp = build_msg_int(tmp, collID);
+       tmp = build_msg_str(tmp, query);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       } 
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )
+               return -1;
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = (*ptr < maxhits) ? *ptr : maxhits;
+               ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each child collection the object record */
+       for(i=0; i<*count; i++) {
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       efree(childIDs);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       efree(childIDs);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       efree(childIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+               *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+int send_getparents(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       int *ptr, *ptr1;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETPARENT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if (-1 == send_hg_msg(sockfd, &msg, length))  {
+               efree(msg.buf);
+               return(-2);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-3);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (*childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = *childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       return(0);
+}
+
+int send_getparentsobj(int sockfd, hw_objectID objectID, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       hw_objectID *childIDs = NULL;
+       char **objptr;
+       int *ptr;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETPARENT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if (-1 == send_hg_msg(sockfd, &msg, length))  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       for(i=0; i<*count; ptr++, i++)
+                               childIDs[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each parent the object record */
+       for(i=0; i<*count; i++) {
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+       efree(childIDs);
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+               *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+       return(0);
+}
+
+int send_pipedocument(int sockfd, char *host, hw_objectID objectID, int mode, int rootid, char **objattr, char **bodytag, char **text, int *count)
+{
+       hg_msg msg, *retmsg;
+       int     length, len;
+       char *tmp, header[80], *head_ptr, *sizestr;
+       struct sockaddr_in      serv_addr;
+       struct hostent      *hostptr;
+       char *hostip = NULL;
+       char *attributes = NULL;
+       char *documenttype;
+       char **anchors;
+       int newfd, fd, port, size, error, ancount;
+       int *ptr;
+
+       if(-1 == (fd = fnCOpenDataCon(sockfd, &port))) {
+                /* not set yet  efree(msg.buf); */
+                  return(-1);
+       }
+
+       /*
+       ** Get information about host
+       */
+       if(host) {
+               if((hostptr = gethostbyname(host)) == NULL) {
+                       php3_error(E_WARNING, "gethostbyname failed for %s", host);
+                       close(fd);
+                       return(-1);
+               }
+       } else {
+               close(fd);
+               return(-1);
+       }
+        
+       switch(hostptr->h_addrtype) {
+               struct in_addr *ptr1;
+               char *ptr;
+               case AF_INET:
+                       ptr = hostptr->h_addr_list[0];
+                       ptr1 = (struct in_addr *) ptr;
+                       hostip = inet_ntoa(*ptr1);
+                       break;
+               default:
+                       close(fd);
+                       return(-1);
+                       break;
+       }
+        
+       /* Bottom half of send_getobject */
+       if(0 > bh_send_getobject(sockfd, objectID)) {
+               close(fd);
+               return -1;
+       }
+
+       /* Upper half of send_getobject */
+       if(0 > (error = uh_send_getobject(sockfd, &attributes))) {
+               close(fd);
+               return error;
+       }
+
+       length = HEADER_LENGTH + sizeof(hw_objectID) + sizeof(int) + strlen(hostip) + 1 + strlen("Refno=0x12345678") + 1;
+       build_msg_header(&msg, length, msgid++, PIPEDOCUMENT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL ) {
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_int(tmp, port);
+       tmp = build_msg_str(tmp, hostip);
+       tmp = build_msg_str(tmp, "Refno=0x12345678");
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               if(attributes) efree(attributes);
+               efree(msg.buf);
+               close(fd);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       /* Just check if the command was understood */
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) {
+               if(attributes) efree(attributes);
+               close(fd);
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if((ptr == NULL) || (*ptr != 0)) {
+               error = *ptr;
+               efree(retmsg);
+               if(retmsg->buf) efree(retmsg->buf);
+               if(attributes) efree(attributes);
+               close(fd);
+               return(error);
+       }
+
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       /* passively open the data connection. The HG server is probably
+           already waiting for us.
+        */
+       len = sizeof(serv_addr);
+       if((newfd = accept(fd, (struct sockaddr *) &serv_addr, &len)) < 0) {
+/*             php3_printf("client: can't open data connection to server\n"); */
+               if(attributes) efree(attributes);
+               close(fd);
+               return(-1);
+       } else {
+               close(fd);
+       }
+
+       /* First of all read the header */
+       head_ptr = header;
+       while((read_to(newfd, head_ptr, 1, rtimeout) == 1) && (*head_ptr != '\0')) {
+               head_ptr++;
+       }
+
+       /* Let's see how big the document is and read it into var text */
+       sizestr = strstr(header, "sz=");
+       if(sizestr) {
+               sizestr += 3;
+               sscanf(sizestr, "%d\n", &size);
+               *count = size;
+               if((size != 0) && (NULL != (*text = malloc(size+1)))) {
+                       read_to(newfd, *text, size, rtimeout);
+                (*text)[size] = '\0';
+               }
+       } else {
+               *text = NULL;
+       }
+
+       /* close the data connection */
+       close(newfd);
+
+       documenttype = fnAttributeValue(attributes, "DocumentType");
+
+       /* Make a copy with strdup (not estrdup), because we want to
+          keep the attributes in hw_document struct.
+       */
+       *objattr = strdup(attributes);
+       efree(attributes);
+
+       if((documenttype != NULL) && (!strcmp(documenttype, "text") != 0)) {
+               if(send_getanchorsobj(sockfd, objectID, &anchors, &ancount) == 0) {
+                       char **destrec, **reldestrec;
+                       DLIST *pAnchorList = NULL;
+
+                       send_getdestforanchorsobj(sockfd, anchors, &destrec, ancount);
+                       send_getreldestforanchorsobj(sockfd, anchors, &reldestrec, ancount, rootid, objectID);
+                       pAnchorList = fnCreateAnchorList(anchors, destrec, reldestrec, ancount, mode);
+                       /* Free only the array, the objrecs has been freed in fnCreateAnchorList() */
+                       if(anchors) efree(anchors);
+                       if(destrec) efree(destrec);
+                       if(reldestrec) efree(reldestrec);
+
+                       if(pAnchorList != NULL) {
+                               char *newtext;
+                               char *body;
+
+                               newtext = fnInsAnchorsIntoText(*text, pAnchorList, &body);
+                               dlst_kill(pAnchorList, fnDeleteAnchor);
+                               *bodytag = strdup(body);
+                               efree(body);
+                               *text = newtext;
+                               *count = strlen(newtext);
+                       }
+               }
+       } else {
+               *bodytag = NULL;
+       }
+
+       if(documenttype) efree(documenttype);
+       return(0);
+}
+
+int send_pipecgi(int sockfd, char *host, hw_objectID objectID, char *cgi_env_str, char **objattr, char **text, int *count)
+{
+       hg_msg msg, *retmsg;
+       int     length, len, new_attr_len;
+       char *tmp, header[80], *head_ptr, *sizestr;
+       struct sockaddr_in      serv_addr;
+       struct hostent      *hostptr;
+       char *hostip = NULL;
+       char *attributes = NULL;
+       char *documenttype, *new_attr;
+       int newfd, fd, port, size, error;
+       int *ptr;
+
+       if(-1 == (fd = fnCOpenDataCon(sockfd, &port))) {
+                 /* not set yet? efree(msg.buf); */
+                  return(-1);
+       }
+
+       /*
+       ** Get information about host
+       */
+       if(host) {
+               if((hostptr = gethostbyname(host)) == NULL) {
+                       php3_error(E_WARNING, "gethostbyname failed for %s", host);
+                       close(fd);
+                       return(-1);
+               }
+       } else {
+               close(fd);
+               return(-1);
+       }
+        
+       switch(hostptr->h_addrtype) {
+               struct in_addr *ptr1;
+               char *ptr;
+               case AF_INET:
+                       ptr = hostptr->h_addr_list[0];
+                       ptr1 = (struct in_addr *) ptr;
+                       hostip = inet_ntoa(*ptr1);
+                       break;
+               default:
+/*                     php3_printf(stderr, "unknown address type\n"); */
+                       break;
+       }
+        
+       /* Bottom half of send_getobject */
+       if(0 > bh_send_getobject(sockfd, objectID)) {
+               close(fd);
+               return -1;
+       }
+
+       /* Upper half of send_getobject */
+       if(0 > (error = uh_send_getobject(sockfd, &attributes))) {
+               close(fd);
+               return error;
+       }
+
+        new_attr_len = strlen(attributes) + strlen(cgi_env_str) + 2;
+        new_attr = malloc(new_attr_len);
+        strcpy(new_attr, attributes);
+        strcat(new_attr, cgi_env_str);
+       length = HEADER_LENGTH + strlen(new_attr) + 1 + sizeof(int) + strlen(hostip) + 1 + sizeof(int) + sizeof(int);
+       build_msg_header(&msg, length, msgid++, PIPECGI_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL ) {
+               if(attributes) efree(attributes);
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, hostip);
+       tmp = build_msg_int(tmp, port);
+       tmp = build_msg_str(tmp, new_attr);
+       tmp = build_msg_int(tmp, 1);
+       tmp = build_msg_int(tmp, 0x12345678);
+       free(new_attr);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               if(attributes) efree(attributes);
+               efree(msg.buf);
+               close(fd);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       /* Just check if the command was understood */
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) {
+               if(attributes) efree(attributes);
+               close(fd);
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if((ptr == NULL) || (*ptr != 0)) {
+               efree(retmsg);
+               if(retmsg->buf) efree(retmsg->buf);
+               if(attributes) efree(attributes);
+               close(fd);
+               return(-1);
+       }
+
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       /* passively open the data connection. The HG server is probably
+           already waiting for us.
+        */
+       len = sizeof(serv_addr);
+       if((newfd = accept(fd, (struct sockaddr *) &serv_addr, &len)) < 0) {
+               if(attributes) efree(attributes);
+               close(fd);
+               return(-1);
+       } else {
+               close(fd);
+       }
+
+       /* First of all read the header */
+       head_ptr = header;
+       while((read_to(newfd, head_ptr, 1, rtimeout) == 1) && (*head_ptr != '\0')) {
+               head_ptr++;
+       }
+
+       /* Let's see how big the document is and read it into var text */
+       sizestr = strstr(header, "sz=");
+       if(sizestr) {
+               sizestr += 3;
+               sscanf(sizestr, "%d\n", &size);
+               *count = size;
+               if((size != 0) && (NULL != (*text = malloc(size+1)))) {
+                 read_to(newfd, *text, size, rtimeout);
+               }
+       } else {
+               *text = NULL;
+       }
+
+       /* close the data connection */
+       close(newfd);
+
+       documenttype = fnAttributeValue(attributes, "DocumentType");
+
+       /* Make a copy with strdup (not estrdup), because we want to
+          keep the attributes in hw_document struct.
+       */
+       *objattr = strdup(attributes);
+       efree(attributes);
+
+       if(documenttype) efree(documenttype);
+       return(0);
+}
+
+int send_putdocument(int sockfd, char *host, hw_objectID parentID, char *objectRec, char *text, int count)
+{
+       hg_msg msg, *retmsg;
+       int length, len;
+       char *tmp, header[80], parms[30], *head_ptr;
+       struct sockaddr_in serv_addr;
+       struct hostent *hostptr;
+       char *hostip = NULL;
+       int newfd, fd, port, objectID, error;
+       int *ptr;
+
+       /* First of all we have to insert the document record */
+        sprintf(parms, "Parent=0x%x", parentID);
+       length = HEADER_LENGTH + strlen(objectRec) + 1 + strlen(parms) + 1;
+
+       build_msg_header(&msg, length, msgid++, INSERTOBJECT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_str(msg.buf, objectRec);
+       tmp = build_msg_str(tmp, parms);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL )  {
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if(0 == (error = *ptr)) {
+               ptr++;
+               objectID = *ptr;
+       } else {
+               efree(retmsg);
+               if(retmsg->buf) efree(retmsg->buf);
+               return(error);
+       }
+
+       efree(retmsg->buf);
+       efree(retmsg);
+
+       /*
+       ** Get information about host
+       */
+       if(host) {
+               if((hostptr = gethostbyname(host)) == NULL) {
+                       php3_error(E_WARNING, "gethostbyname failed for %s", host);
+                       /* close(fd); fd is not set yet */
+                       return(-1);
+               }
+       } else {
+               /* close(fd); fd is not set yet */
+               return(-1);
+       }
+        
+       switch(hostptr->h_addrtype) {
+               struct in_addr *ptr1;
+               char *ptr;
+               case AF_INET:
+                       ptr = hostptr->h_addr_list[0];
+                       ptr1 = (struct in_addr *) ptr;
+                       hostip = inet_ntoa(*ptr1);
+                       break;
+               default:
+/*                     fprintf(stderr, "unknown address type\n"); */
+                       break;
+       }
+        
+       if(-1 == (fd = fnCOpenDataCon(sockfd, &port))) {
+                  efree(msg.buf);
+                  return(-1);
+       }
+
+       /* Start building the PUTDOCUMENT message. I works even if
+          the Refno is skipped. I guess the path can be omitted too. */
+       length = HEADER_LENGTH + sizeof(hw_objectID) + sizeof(int) + strlen(hostip) + 1 + strlen("Hyperwave") + 1+ strlen("Refno=0x12345678") + 1;
+
+       build_msg_header(&msg, length, msgid++, PUTDOCUMENT_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )        {
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+       tmp = build_msg_int(tmp, port);
+       tmp = build_msg_str(tmp, hostip);
+       tmp = build_msg_str(tmp, "Hyperwave");
+       tmp = build_msg_str(tmp, "Refno=0x12345678");
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               close(fd);
+               return(-1);
+       }
+       efree(msg.buf);
+
+       /* passively open the data connection. The HG server is probably
+           already waiting for us.
+        */
+       len = sizeof(serv_addr);
+       if((newfd = accept(fd, (struct sockaddr *) &serv_addr, &len)) < 0) {
+               close(fd);
+               return(-1);
+       } else {
+               close(fd);
+       }
+
+       /* First of all write the header. According to the documentation
+          there should be a header first. Well, after some investigation
+          with tcpdump I found out, that Harmony and wavemaster don't
+          sent it. The also do not sent the Refno in the PUTDOCUMENT msg.
+          Anyway, we sent both. */
+       head_ptr = header;
+       sprintf(header, "HGHDR\nsz=%d\nref=12345678\n", count);
+       len = strlen(header) + 1;
+       if(len != write_to(newfd, header, len, wtimeout)) {
+               close(newfd);
+               return(-1);
+       }
+
+       /* And now the document */
+       if(count != write_to(newfd, text, count, wtimeout)) {
+               close(newfd);
+               return(-1);
+       }
+       
+       /* The data connection has to be close before the return
+          msg can be read. The server will not sent it before. */
+       close(newfd);
+
+       /* Just check if the command was understood */
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) {
+               close(fd);
+               return(-1);
+       }
+
+       ptr = (int *) retmsg->buf;
+       if((ptr == NULL) || (*ptr != 0)) {
+               efree(retmsg);
+               if(retmsg->buf) efree(retmsg->buf);
+               close(fd);
+               return(-1);
+       }
+
+       efree(retmsg);
+       efree(retmsg->buf);
+
+       return(0);
+}
+
+int send_getsrcbydest(int sockfd, hw_objectID objectID, char ***childrec, int *count)
+{
+       hg_msg msg, *retmsg;
+       int length, i, error;
+       char *tmp;
+       int *childIDs = NULL;
+       char **objptr;
+       int *ptr, *ptr1;
+
+       length = HEADER_LENGTH + sizeof(hw_objectID);
+
+       build_msg_header(&msg, length, msgid++, GETSRCBYDEST_MESSAGE);
+
+       if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+       tmp = build_msg_int(msg.buf, objectID);
+
+       if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+               efree(msg.buf);
+               return(-1);
+       }
+
+       efree(msg.buf);
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) 
+               return(-1);
+
+       ptr = (int *) retmsg->buf;
+       if(ptr == NULL) {
+               if(retmsg) efree(retmsg);
+               return -1;
+       }
+       if(*ptr++ == 0) {
+               *count = *ptr;
+               ptr++;
+               if(NULL != (childIDs = emalloc(*count * sizeof(hw_objectID)))) {
+                       ptr1 = childIDs;
+                       for(i=0; i<*count; ptr++, i++)
+                               ptr1[i] = *ptr;
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               } else {
+                       efree(retmsg->buf);
+                       efree(retmsg);
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+       } else {
+               error = *((int *) retmsg->buf);
+               efree(retmsg->buf);
+               efree(retmsg);
+               return error;
+       }
+
+       /* Now get for each source the object record */
+       for(i=0; i<*count; i++) {
+               length = HEADER_LENGTH + sizeof(hw_objectID);
+               build_msg_header(&msg, length, childIDs[i], GETOBJECT_MESSAGE);
+
+               if ( (msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*                     perror("send_command"); */
+                       lowerror = LE_MALLOC;
+                       return(-1);
+               }
+
+               tmp = build_msg_int(msg.buf, childIDs[i]);
+
+               if ( send_hg_msg(sockfd, &msg, length) == -1 )  {
+                       efree(msg.buf);
+                       return(-1);
+                       }
+
+               efree(msg.buf);
+       }
+
+       if(NULL == (objptr = (char **) emalloc(*count * sizeof(hw_objrec *)))) {
+               /* if emalloc fails, get at least all remaining  messages from server */
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       efree(retmsg->buf);
+                       efree(retmsg);
+               }
+               *childrec = NULL;
+               lowerror = LE_MALLOC;
+               return(-1);
+       } else {
+               *childrec = objptr;
+
+               for(i=0; i<*count; i++) {
+                       retmsg = recv_hg_msg(sockfd);
+                       if ( retmsg != NULL )  {
+                               if(0 == (int) *(retmsg->buf)) {
+                                       *objptr = estrdup(retmsg->buf+sizeof(int));
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               } else {
+                                       *objptr = NULL;
+                                       objptr++;
+                                       efree(retmsg->buf);
+                                       efree(retmsg);
+                               }
+                       }
+               }
+       }
+
+       return(0);
+}
+
+char *get_hw_info(hw_connection *conn)
+       {
+       char temp[200];
+       int len;
+       struct sockaddr_in serv_addr;
+
+       len = sizeof (serv_addr);
+       if(getsockname(conn->socket, (struct sockaddr *)&serv_addr, &len) < 0)
+               return(NULL);
+
+       sprintf(temp, "%s, %s, %d, %s, %d, %d", conn->server_string, conn->hostname,
+                                      conn->version, conn->username,
+                                      serv_addr.sin_port, conn->swap_on);
+       return(estrdup(temp));
+       }
+
+static int send_hg_msg(int sockfd, hg_msg *msg, int length)
+{
+     char *buf, *tmp;
+
+#ifdef HW_DEBUG
+       php3_printf("<B>Sending msg: </B>type = %d -- id = %d<BR>\n", msg->msg_type, msg->version_msgid);
+#endif
+     if ( length < HEADER_LENGTH )  {
+/*          fprintf(stderr, "send_hg_msg: bad msg\n"); */
+          return(-1);
+     }
+
+     if ( (tmp = buf = (char *)emalloc(length)) == NULL )  {
+/*             perror("send_hg_msg"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+     }
+
+     memcpy(tmp, (char *) &(msg->length), 4);
+     tmp += 4;
+     memcpy(tmp, (char *) &(msg->version_msgid), 4);
+     tmp += 4;
+     memcpy(tmp, (char *) &(msg->msg_type), 4);
+     if ( msg->length > HEADER_LENGTH )  {
+          tmp += 4;
+          memcpy(tmp, msg->buf, length-HEADER_LENGTH);
+     }
+
+     if ( hg_write(sockfd, buf, length) == -1 )  {
+          efree(buf);
+          return(-1);
+     }
+
+     efree(buf);
+     return(0);
+}
+
+
+int send_ready(int sockfd)
+{
+     hg_msg ready_msg;
+
+     build_msg_header(&ready_msg, HEADER_LENGTH, version, READY_MESSAGE);
+     ready_msg.buf = NULL;
+
+     if ( send_hg_msg(sockfd, &ready_msg, HEADER_LENGTH) == -1 )  {
+          return(-1);
+     }
+
+     return(0);
+}
+
+
+int send_command(int sockfd, int command, char **answer)
+{
+       hg_msg comm_msg, *retmsg;
+       char *comm_str, *tmp;
+       int  respond = 1;
+       int  length;
+
+       if ( command == STAT_COMMAND )
+               comm_str = STAT_COMMAND_STR;
+       else
+               comm_str = WHO_COMMAND_STR;
+       length = HEADER_LENGTH + sizeof(respond) + strlen(comm_str) + 1;
+
+       build_msg_header(&comm_msg, length, msgid++, COMMAND_MESSAGE);
+
+       if ( (comm_msg.buf = (char *)emalloc(length-HEADER_LENGTH)) == NULL )  {
+/*             perror("send_command"); */
+               lowerror = LE_MALLOC;
+               return(-1);
+       }
+
+
+       tmp = build_msg_int(comm_msg.buf, respond);
+       tmp = build_msg_str(tmp, comm_str);
+
+
+       if ( send_hg_msg(sockfd, &comm_msg, length) == -1 )  {
+               efree(comm_msg.buf);
+               return(-1);
+       }
+       efree(comm_msg.buf);
+
+       /* Just check if the command was understood */
+       retmsg = recv_hg_msg(sockfd);
+       if ( retmsg == NULL ) {
+               return(-1);
+       }
+
+       efree(retmsg);
+       *answer = retmsg->buf;
+
+       return(0);
+}
+
+
+static void build_msg_header(hg_msg *msg, int length, int version_msgid, int msg_type)
+{
+     if ( swap_on )  {
+          msg->length  = swap(length);
+          msg->version_msgid = swap(version_msgid);
+          msg->msg_type  = swap(msg_type);
+     }
+     else  {
+          msg->length  = length;
+          msg->version_msgid = version_msgid;
+          msg->msg_type  = msg_type;
+     }
+}
+
+
+static char *build_msg_int(char *buf, int val) {
+       int tmp;
+
+#ifdef HW_DEBUG
+       php3_printf("   Added int to header: <B>%d</B><BR>\n", val);
+#endif
+       tmp = swap_on ? swap(val) : val;
+       memcpy(buf, (char *)&tmp, 4);
+
+       return(buf+4);
+}
+
+
+static char *build_msg_str(char *buf, char *str)
+{
+     int len = strlen(str)+1;
+
+#ifdef HW_DEBUG
+       php3_printf("   Added str to header: <B>%s</B> (%d)<BR>\n", str, strlen(str));
+#endif
+
+     memcpy(buf, str, len);
+
+     return(buf+len);
+}
+
+
+static int swap(int val)
+{
+     int tmp;
+
+     ((char*)&tmp)[0] = ((char*)&val)[3];
+     ((char*)&tmp)[1] = ((char*)&val)[2];
+     ((char*)&tmp)[2] = ((char*)&val)[1];
+     ((char*)&tmp)[3] = ((char*)&val)[0];
+
+     return(tmp);
+}
+
+
+void close_hg_connection(int sockfd)
+{
+     shutdown(sockfd, 2);
+     close(sockfd);
+}
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
+
diff --git a/ext/hyperwave/hg_comm.h b/ext/hyperwave/hg_comm.h
new file mode 100644 (file)
index 0000000..d4e1892
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of the GNU General Public License as published by |
+   | the Free Software Foundation; either version 2 of the License, or    |
+   | (at your option) any later version.                                  |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            |
+   +----------------------------------------------------------------------+
+   | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
+   +----------------------------------------------------------------------+
+ */
+
+
+/* $Id$ */
+
+#ifndef _HG_COMM_H
+#define _HG_COMM_H
+
+#if HYPERWAVE
+
+#include "hw_error.h"
+#define HG_SERVER_PORT   418
+
+#define F_DISTRIBUTED 0x80000000
+#define F_COMPRESSED  0x40000000
+#define F_VERSION     0x00003fff
+#define VERSION       717L     /* 7.05 */
+
+#define HEADER_LENGTH 12
+
+#define STAT_COMMAND_STR  "stat"
+#define WHO_COMMAND_STR   "who"
+#define STAT_COMMAND      1
+#define WHO_COMMAND       2
+
+#define GETDOCBYANCHOR_MESSAGE        2
+#define GETCHILDCOLL_MESSAGE          3
+#define GETPARENT_MESSAGE             4
+#define GETCHILDDOCCOLL_MESSAGE       5
+#define GETOBJECT_MESSAGE             7
+#define GETANCHORS_MESSAGE            8
+#define GETOBJBYQUERY_MESSAGE         9
+#define GETOBJBYQUERYCOLL_MESSAGE    10
+#define GETTEXT_MESSAGE              12
+#define INSDOC_MESSAGE               14
+#define INSCOLL_MESSAGE              17
+#define GETSRCBYDEST_MESSAGE         19
+#define MVCPDOCSCOLL_MESSAGE         22
+#define MVCPCOLLSCOLL_MESSAGE        23
+#define IDENTIFY_MESSAGE             24
+#define READY_MESSAGE                25
+#define COMMAND_MESSAGE              26
+#define CHANGEOBJECT_MESSAGE         27
+#define EDITTEXT_MESSAGE             28
+#define GETANDLOCK_MESSAGE           29
+#define UNLOCK_MESSAGE               30
+#define INCOLLECTIONS_MESSAGE        31
+#define INSERTOBJECT_MESSAGE         32
+#define PIPEDOCUMENT_MESSAGE         36
+#define DELETEOBJECT_MESSAGE         37
+#define PUTDOCUMENT_MESSAGE          38
+#define GETREMOTE_MESSAGE            39
+#define GETREMOTECHILDREN_MESSAGE    40
+#define CHILDREN_MESSAGE             44
+#define GETCGI_MESSAGE               45
+#define PIPECGI_MESSAGE              46
+
+#define HW_DEFAULT_LINK               0
+#define HW_IMAGE_LINK                 1
+#define HW_BACKGROUND_LINK            2
+#define HW_INTAG_LINK                 3
+#define HW_APPLET_LINK                4
+
+#define COPY                          0
+#define MOVE                          1
+#define DOCUMENT                      0
+#define COLLECTION                    1
+
+/* Low error messages */
+#define LE_MALLOC                    -1
+
+typedef struct {
+       int id;                         /* object ID of anchor */
+       int tanchor;            /* Type of anchor. Can be 1=Src, 2=Dest */
+       int start;                      /* start of anchor */
+       int end;                                /* end of anchor */
+       char *nameanchor;                       /* name tag attribute of destination document */
+       /* if anchor is of type Src the following are used as well */
+       char *destdocname;                      /* name of destination document */
+       char *link;                     /* url for external destination */
+       int linktype;           /* type of link. see above */
+       char *tagattr;          /* more attributes of tag, like Border=0 */
+       char *htmlattr; /* */
+       char *codebase;         /* codebase of applet */
+       char *code;             /* code of applet */
+       char *fragment;         /* name link of Src */
+
+       /* if anchor is of type Dest the following are used as well */
+       char *keyword;          /* name link of Dest */
+       } ANCHOR;
+
+typedef struct  {
+     int  length;
+     int  version_msgid;
+     int  msg_type;
+     char *buf;
+} hg_msg;
+
+typedef struct {
+       int socket;
+       int swap_on;
+       int version;
+       char *server_string;
+        char *hostname;
+        char *username;
+       int lasterror;
+       int linkroot;
+} hw_connection;
+
+typedef int hw_objectID;
+typedef char hw_objrec;
+
+extern void set_swap(int do_swap);
+extern int  open_hg_connection(char *server_name, int port);
+extern void close_hg_connection(int sockfd);
+extern int initialize_hg_connection(int sockfd, int *do_swap, int *version, char **userdata, char **server_string, char *username, char *password);
+
+extern int send_ready(int sockfd);
+extern int send_command(int sockfd, int command, char **answer);
+
+extern hg_msg *recv_hg_msg(int sockfd);
+extern hg_msg *recv_ready(int sockfd);
+extern hg_msg *recv_command(int sockfd);
+
+extern char *fnInsStr(char *str, int pos, char *insstr);
+extern int fnAttributeCompare(char *object, char *attrname, char *value);
+extern int getrellink(int sockfd, int rootID, int thisID, int destID, char **reldesstr);
+
+extern int send_deleteobject(int sockfd, hw_objectID objectID);
+extern int send_changeobject(int sockfd, hw_objectID objectID, char *mod);
+extern int send_getobject(int sockfd, hw_objectID objectID, char **attributes);
+extern int send_getandlock(int sockfd, hw_objectID objectID, char **attributes);
+extern int send_unlock(int sockfd, hw_objectID objectID);
+extern int send_gettext(int sockfd, hw_objectID objectID, int mode, int rootid, char **objattr, char **bodytag, char **text, int *count);
+extern int send_edittext(int sockfd, char *objattr, char *text);
+extern int send_getcgi(int sockfd, hw_objectID objectID, char *cgi_env_str, char **objattr, char **text, int *count);
+extern int send_getremote(int sockfd, hw_objectID objectID, char **objattr, char **text, int *count);
+extern int send_getremotechildren(int sockfd, char *attributes, char **text, int **childIDs, int *count);
+extern int send_docbyanchor(int sockfd, hw_objectID objectID, hw_objectID *anchorID);
+extern int send_docbyanchorobj(int sockfd, hw_objectID objectID, char **objrec);
+extern int send_mvcpdocscollscoll(int sockfd, hw_objectID *objectIDs, int count, int from, int dest, int cpmv, int docscoll);
+extern int send_childrenobj(int sockfd, hw_objectID objectID, char ***childrec, int *count);
+extern int send_getchildcoll(int sockfd, int objectID, hw_objectID **childIDs, int *count);
+extern int send_getchildcollobj(int sockfd, hw_objectID objectID, hw_objrec ***childrec, int *count);
+extern int send_getchilddoccoll(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count);
+extern int send_getchilddoccollobj(int sockfd, hw_objectID objectID, hw_objrec ***childrec, int *count);
+extern int send_getanchors(int sockfd, hw_objectID objectID, hw_objectID **anchorIDs, int *count);
+extern int send_getanchorsobj(int sockfd, hw_objectID objectID, char ***childrec, int *count);
+extern int send_getobjbyquery(int sockfd, char *query, int maxhits, hw_objectID **childIDs, int *count);
+extern int send_getobjbyqueryobj(int sockfd, char *query, int maxhits, char ***childrec, int *count);
+extern int send_getobjbyquerycoll(int sockfd, hw_objectID collID, char *query, int maxhits, hw_objectID **childIDs, int *count);
+extern int send_getobjbyquerycollobj(int sockfd, hw_objectID collID, char *query, int maxhits, char ***childrec, int *count);
+extern int send_identify(int sockfd, char *name, char *passwd, char **userdata);
+extern int send_getparents(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count);
+extern int send_children(int sockfd, hw_objectID objectID, hw_objectID **childIDs, int *count);
+extern int send_getparentsobj(int sockfd, hw_objectID objectID, char ***childrec, int *count);
+extern int send_pipedocument(int sockfd, char *hostname, hw_objectID objectID, int mode, int rootid, char** objattr, char **bodytag, char **text, int *count);
+extern int send_pipecgi(int sockfd, char *host, hw_objectID objectID, char *cgi_env_str, char **objattr, char **text, int *count);
+extern int send_putdocument(int sockfd, char *hostname, hw_objectID objectID, char *objectRec, char *text, int count);
+extern int send_inscoll(int sockfd, hw_objectID objectID, char *objrec, hw_objectID *new_objectID);
+extern int send_insertobject(int sockfd, char *objrec, char *parms, hw_objectID *objectID);
+extern int send_insdoc(int sockfd, hw_objectID objectID, char *objrec, char *text, hw_objectID *new_objectID);
+extern int send_incollections(int sockfd, int retcol, int cobjids, hw_objectID *objectIDs, int ccollids, hw_objectID *collIDs, int *count, hw_objectID **retIDs);
+extern int send_getsrcbydest(int sockfd, hw_objectID objid, char ***childrec, int *count);
+extern int send_dummy(int sockfd, hw_objectID objectID, int msgid, char **attributes);
+extern char *get_hw_info(hw_connection *conn);
+
+#define send_mvcpdocscoll(sockfd,objectIDs,count,from,dest,mvcp) \
+               send_mvcpdocscollscoll(sockfd,objectIDs,count,from,dest,mvcp,DOCUMENT)
+#define send_mvcpcollscoll(sockfd,objectIDs,count,from,dest,mvcp) \
+               send_mvcpdocscollscoll(sockfd,objectIDs,count,from,dest,mvcp,COLLECTION)
+
+#endif
+#endif
diff --git a/ext/hyperwave/hw.c b/ext/hyperwave/hw.c
new file mode 100644 (file)
index 0000000..db1da99
--- /dev/null
@@ -0,0 +1,3062 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of the GNU General Public License as published by |
+   | the Free Software Foundation; either version 2 of the License, or    |
+   | (at your option) any later version.                                  |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            |
+   +----------------------------------------------------------------------+
+   | Authors: Uwe Steinmann                                               |
+   |                                                                      |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+#if COMPILE_DL
+#include "dl/phpdl.h"
+#endif
+
+#include <stdlib.h>
+
+#if !(WIN32|WINNT)
+#include "config.h"
+#endif
+#include "php.h"
+#include "functions/head.h"
+
+#if HYPERWAVE
+
+
+#include "hw.h"
+
+#if APACHE
+#  ifndef DEBUG
+#  undef palloc
+#  endif
+#endif
+
+hw_module php3_hw_module;
+
+function_entry hw_functions[] = {
+       {"hw_connect",                  php3_hw_connect,                NULL},
+       {"hw_pconnect",                 php3_hw_pconnect,               NULL},
+       {"hw_close",                    php3_hw_close,                  NULL},
+       {"hw_root",                     php3_hw_root,                   NULL},
+       {"hw_info",                     php3_hw_info,                   NULL},
+       {"hw_connection_info",          php3_hw_connection_info,        NULL},
+       {"hw_error",                    php3_hw_error,                  NULL},
+       {"hw_errormsg",                 php3_hw_errormsg,               NULL},
+       {"hw_getparentsobj",            php3_hw_getparentsobj,          NULL},
+       {"hw_getparents",               php3_hw_getparents,             NULL},
+       {"hw_children",                 php3_hw_children,               NULL},
+       {"hw_childrenobj",              php3_hw_childrenobj,            NULL},
+       {"hw_getchildcoll",             php3_hw_getchildcoll,           NULL},
+       {"hw_getchildcollobj",          php3_hw_getchildcollobj,        NULL},
+       {"hw_getobject",                php3_hw_getobject,              NULL},
+       {"hw_getandlock",               php3_hw_getandlock,             NULL},
+       {"hw_unlock",                   php3_hw_unlock,                 NULL},
+       {"hw_gettext",                  php3_hw_gettext,                NULL},
+       {"hw_edittext",                 php3_hw_edittext,               NULL},
+       {"hw_getcgi",                   php3_hw_getcgi,                 NULL},
+       {"hw_getremote",                php3_hw_getremote,              NULL},
+       {"hw_getremotechildren",        php3_hw_getremotechildren,      NULL},
+       {"hw_pipedocument",             php3_hw_pipedocument,           NULL},
+       {"hw_pipecgi",                  php3_hw_pipecgi,                NULL},
+       {"hw_insertdocument",           php3_hw_insertdocument,         NULL},
+       {"hw_mv",                       php3_hw_mv,                     NULL},
+       {"hw_cp",                       php3_hw_cp,                     NULL},
+       {"hw_deleteobject",             php3_hw_deleteobject,           NULL},
+       {"hw_changeobject",             php3_hw_changeobject,           NULL},
+       {"hw_docbyanchor",              php3_hw_docbyanchor,            NULL},
+       {"hw_docbyanchorobj",           php3_hw_docbyanchorobj,         NULL},
+       {"hw_getobjectbyquery",         php3_hw_getobjectbyquery,       NULL},
+       {"hw_getobjectbyqueryobj",      php3_hw_getobjectbyqueryobj,    NULL},
+       {"hw_getobjectbyquerycoll",     php3_hw_getobjectbyquerycoll,   NULL},
+       {"hw_getobjectbyquerycollobj",  php3_hw_getobjectbyquerycollobj,NULL},
+       {"hw_getchilddoccoll",          php3_hw_getchilddoccoll,        NULL},
+       {"hw_getchilddoccollobj",       php3_hw_getchilddoccollobj,     NULL},
+       {"hw_getanchors",               php3_hw_getanchors,             NULL},
+       {"hw_getanchorsobj",            php3_hw_getanchorsobj,          NULL},
+       {"hw_getusername",              php3_hw_getusername,            NULL},
+       {"hw_setlinkroot",              php3_hw_setlinkroot,            NULL},
+       {"hw_identify",                 php3_hw_identify,               NULL},
+       {"hw_free_document",            php3_hw_free_document,          NULL},
+       {"hw_new_document",             php3_hw_new_document,           NULL},
+       {"hw_output_document",          php3_hw_output_document,        NULL},
+       {"hw_outputdocument",           php3_hw_output_document,        NULL},
+       {"hw_document_size",            php3_hw_document_size,          NULL},
+       {"hw_documentsize",             php3_hw_document_size,          NULL},
+       {"hw_document_attributes",      php3_hw_document_attributes,    NULL},
+       {"hw_documentattributes",       php3_hw_document_attributes,    NULL},
+       {"hw_document_bodytag",         php3_hw_document_bodytag,       NULL},
+       {"hw_documentbodytag",          php3_hw_document_bodytag,       NULL},
+       {"hw_document_content",         php3_hw_document_content,       NULL},
+       {"hw_objrec2array",             php3_hw_objrec2array,           NULL},
+       {"hw_array2objrec",             php3_hw_array2objrec,           NULL},
+       {"hw_incollections",            php3_hw_incollections,          NULL},
+       {"hw_inscoll",                  php3_hw_inscoll,                NULL},
+       {"hw_insertobject",             php3_hw_insertobject,           NULL},
+       {"hw_insdoc",                   php3_hw_insdoc,                 NULL},
+       {"hw_getsrcbydestobj",          php3_hw_getsrcbydestobj,        NULL},
+       {"hw_getrellink",               php3_hw_getrellink,             NULL},
+       {"hw_who",                      php3_hw_who,                    NULL},
+       {"hw_stat",                     php3_hw_stat,                   NULL},
+       {"hw_dummy",                    php3_hw_dummy,                  NULL},
+       {NULL, NULL, NULL}
+};
+
+php3_module_entry hw_module_entry = {
+       "HyperWave", hw_functions, php3_minit_hw, NULL, NULL, NULL, php3_info_hw, 0, 0, 0, NULL
+};
+
+void print_msg(hg_msg *msg, char *str, int txt);
+
+#if COMPILE_DL
+DLEXPORT php3_module_entry *get_module(void) { return &hw_module_entry; }
+#endif
+
+void _close_hw_link(hw_connection *conn)
+{
+       if(conn->hostname)
+               free(conn->hostname);
+       if(conn->username)
+               free(conn->username);
+       close(conn->socket);
+       free(conn);
+       php3_hw_module.num_links--;
+}
+
+void _close_hw_plink(hw_connection *conn)
+{
+       if(conn->hostname)
+               free(conn->hostname);
+       if(conn->username)
+               free(conn->username);
+       close(conn->socket);
+       free(conn);
+       php3_hw_module.num_links--;
+       php3_hw_module.num_persistent--;
+}
+
+void _free_hw_document(hw_document *doc)
+{
+       if(doc->data)
+               free(doc->data);
+       if(doc->attributes)
+               free(doc->attributes);
+       if(doc->bodytag)
+               free(doc->bodytag);
+       free(doc);
+}
+
+/* creates an array in return value and frees all memory
+ * Also adds as an assoc. array at the end of the return array with
+ * statistics.
+ */
+int make_return_objrec(pval **return_value, char **objrecs, int count)
+{
+       pval stat_arr;
+       int i;
+       int hidden, collhead, fullcollhead, total;
+        int collheadnr, fullcollheadnr;
+
+       if (array_init(*return_value) == FAILURE) {
+               /* Ups, failed! Let's at least free the memory */
+               for(i=0; i<count; i++)
+                       efree(objrecs[i]);
+               efree(objrecs);
+               return -1;
+       }
+
+       hidden = collhead = fullcollhead = total = 0;
+        collheadnr = fullcollheadnr = -1;
+       for(i=0; i<count; i++) {
+               /* Fill the array with entries. No need to free objrecs[i], since
+                * it is not duplicated in add_next_index_string().
+                */
+               if(NULL != objrecs[i]) {
+                       if(0 == fnAttributeCompare(objrecs[i], "PresentationHints", "Hidden"))
+                               hidden++;
+                       if(0 == fnAttributeCompare(objrecs[i], "PresentationHints", "CollectionHead")) {
+                               collhead++;
+                               collheadnr = total;
+                       }
+                       if(0 == fnAttributeCompare(objrecs[i], "PresentationHints", "FullCollectionHead")) {
+                               fullcollhead++;
+                               fullcollheadnr = total;
+                       }
+                       total++;
+                       add_next_index_string(*return_value, objrecs[i], 0);
+               }
+       }
+       efree(objrecs);
+
+       /* Array for statistics */
+       if (array_init(&stat_arr) == FAILURE) {
+               return -1;
+       }
+
+       add_assoc_long(&stat_arr, "Hidden", hidden);
+       add_assoc_long(&stat_arr, "CollectionHead", collhead);
+       add_assoc_long(&stat_arr, "FullCollectionHead", fullcollhead);
+       add_assoc_long(&stat_arr, "Total", total);
+       add_assoc_long(&stat_arr, "CollectionHeadNr", collheadnr);
+       add_assoc_long(&stat_arr, "FullCollectionHeadNr", fullcollheadnr);
+
+       /* Add the stat array */
+       _php3_hash_next_index_insert((*return_value)->value.ht, &stat_arr, sizeof(pval), NULL);
+
+       /* The title array can now be freed, but I don't know how */
+       return 0;
+}
+
+/*
+** creates an array return value from object record
+*/
+int make_return_array_from_objrec(pval **return_value, char *objrec) {
+       pval title_arr, desc_arr;
+       char *attrname, *str, *temp, language[3], *title;
+       int iTitle, iDesc;
+       int hasTitle = 0;
+       int hasDescription = 0;
+
+       if (array_init(*return_value) == FAILURE) {
+               (*return_value)->type = IS_STRING;
+               (*return_value)->value.str.val = empty_string;
+               (*return_value)->value.str.len = 0;
+               return -1;
+       }
+
+       /* Array for titles. Only if we have at least one title */
+/*     if(0 == strncmp(objrec, "Title=", 6)) { */
+               if (array_init(&title_arr) == FAILURE) {
+                       return -1;
+               }
+               hasTitle = 1;
+/*     } */
+
+       /* Array for Descriptions. Only if we have at least one description */
+/*     if(0 == strncmp(objrec, "Description=", 12)) { */
+               if (array_init(&desc_arr) == FAILURE) {
+                       return -1;
+               }
+               hasDescription = 1;
+/*     } */
+
+       /* Fill Array of titles and descriptions */
+       temp = estrdup(objrec);
+       attrname = strtok(temp, "\n");
+       while(attrname != NULL) {
+               str = attrname;
+               iTitle = 0;
+               iDesc = 0;
+               if(0 == strncmp(attrname, "Title=", 6)) {
+                       str += 6;
+                       iTitle = 1;
+               } else if(0 == strncmp(attrname, "Description=", 12)) {
+                       str += 12;
+                       iDesc = 1;
+               }
+               if(iTitle || iDesc) {                   /* Poor error check if end of string */
+                       if(str[2] == ':') {
+                               str[2] = '\0';
+                               strcpy(language, str);
+                               str += 3;
+                       } else
+                               strcpy(language, "xx");
+
+                       title = str;
+/*                     while((*str != '=') && (*str != '\0'))
+                               str++;
+                       *str = '\0';
+*/                     if(iTitle)
+                               add_assoc_string(&title_arr, language, title, 1);
+                       else
+                               add_assoc_string(&desc_arr, language, title, 1);
+               }
+               attrname = strtok(NULL, "\n");
+       }
+       efree(temp);
+
+       /* Add the title array, if we have one */
+       if(hasTitle) {
+               _php3_hash_update((*return_value)->value.ht, "Title", 6, &title_arr, sizeof(pval), NULL);
+
+               /* The title array can now be freed, but I don't know how */
+       }
+
+       if(hasDescription) {
+       /* Add the description array, if we have one */
+               _php3_hash_update((*return_value)->value.ht, "Description", 12, &desc_arr, sizeof(pval), NULL);
+
+               /* The description array can now be freed, but I don't know how */
+       }
+
+       /* All other attributes. Make a another copy first */
+       temp = estrdup(objrec);
+       attrname = strtok(temp, "\n");
+       while(attrname != NULL) {
+               str = attrname;
+               /* We don't want to insert titles a second time */
+               if((0 != strncmp(attrname, "Title=", 6)) &&
+                  (0 != strncmp(attrname, "Description=", 12))) {
+                       while((*str != '=') && (*str != '\0'))
+                               str++;
+                       *str = '\0';
+                       str++;
+                       add_assoc_string(*return_value, attrname, str, 1);
+               }
+               attrname = strtok(NULL, "\n");
+       }
+       efree(temp);
+
+       return(0);
+}
+
+static char * make_objrec_from_array(HashTable *lht) {
+       int i, count, keytype;
+       ulong length;
+       char *key, str[1024], *objrec = NULL;
+       pval *keydata;
+
+       if(NULL == lht)
+               return NULL;
+
+       if(0 == (count = _php3_hash_num_elements(lht)))
+               return NULL;
+       
+       _php3_hash_internal_pointer_reset(lht);
+       objrec = malloc(1);
+       *objrec = '\0';
+       for(i=0; i<count; i++) {
+               keytype = _php3_hash_get_current_key(lht, &key, &length);
+               if(HASH_KEY_IS_STRING == keytype) {
+                       _php3_hash_get_current_data(lht, (void **) &keydata);
+                       switch(keydata->type) {
+                               case IS_STRING:
+                                       sprintf(str, "%s=%s\n", key, keydata->value.str.val);
+                                       break;
+                               case IS_LONG:
+                                       sprintf(str, "%s=0x%lX\n", key, keydata->value.lval);
+                                       break;
+                       }
+                       efree(key);
+                       objrec = realloc(objrec, strlen(objrec)+strlen(str)+1);
+                       strcat(objrec, str);
+               }
+               _php3_hash_move_forward(lht);
+       }
+       return objrec;
+}
+
+static int * make_ints_from_array(HashTable *lht) {
+       int i, count;
+       int *objrec = NULL;
+       pval *keydata;
+
+       if(NULL == lht)
+               return NULL;
+
+       if(0 == (count = _php3_hash_num_elements(lht)))
+               return NULL;
+       
+       _php3_hash_internal_pointer_reset(lht);
+       if(NULL == (objrec = emalloc(count*sizeof(int))))
+               return NULL;
+       for(i=0; i<count; i++) {
+               _php3_hash_get_current_data(lht, (void **) &keydata);
+               switch(keydata->type) {
+                       case IS_LONG:
+                               objrec[i] = keydata->value.lval;
+                               break;
+                       default:
+                               objrec[i] = 0;
+               }
+               _php3_hash_move_forward(lht);
+       }
+       return objrec;
+}
+
+int php3_minit_hw(INIT_FUNC_ARGS) {
+
+       if (cfg_get_long("hw.allow_persistent",&php3_hw_module.allow_persistent)==FAILURE) {
+               php3_hw_module.allow_persistent=1;
+       }
+       if (cfg_get_long("hw.max_persistent",&php3_hw_module.max_persistent)==FAILURE) {
+               php3_hw_module.max_persistent=-1;
+       }
+       if (cfg_get_long("hw.max_links",&php3_hw_module.max_links)==FAILURE) {
+               php3_hw_module.max_links=-1;
+       }
+       php3_hw_module.num_persistent=0;
+       php3_hw_module.le_socketp = register_list_destructors(_close_hw_link,NULL);
+       php3_hw_module.le_psocketp = register_list_destructors(NULL,_close_hw_plink);
+       php3_hw_module.le_document = register_list_destructors(_free_hw_document,NULL);
+
+       return SUCCESS;
+}
+
+static void php3_hw_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
+{
+       pval *argv[4];
+       int argc;
+       int sockfd;
+       int port = 0;
+       char *host = NULL;
+       char *userdata = NULL;
+       char *server_string = NULL;
+       char *username = NULL;
+       char *password = NULL;
+       char *hashed_details;
+       char *str = NULL;
+       char buffer[20];
+       int hashed_details_length;
+       hw_connection *ptr;
+       int do_swap;
+       int version = 0;
+       TLS_VARS;
+       
+       argc = ARG_COUNT(ht);
+       switch(argc) {
+               case 2:
+                       if (getParametersArray(ht, argc, argv) == FAILURE) {
+                               WRONG_PARAM_COUNT;
+                       }
+                       break;
+               case 4:
+                       if (getParametersArray(ht, argc, argv) == FAILURE) {
+                               WRONG_PARAM_COUNT;
+                       }
+                       break;
+               default:
+                       WRONG_PARAM_COUNT;
+       }
+
+       /* Host: */
+       convert_to_string(argv[0]);
+       host = (char *) estrndup(argv[0]->value.str.val,argv[0]->value.str.len);
+
+       /* Port: */
+       convert_to_long(argv[1]);
+       port = argv[1]->value.lval;
+
+       /* Username and Password */
+       if(argc > 2) {
+               /* Username */
+               convert_to_string(argv[2]);
+               username = (char *) estrndup(argv[2]->value.str.val,argv[2]->value.str.len);
+               /* Password */
+               convert_to_string(argv[3]);
+               password = (char *) estrndup(argv[3]->value.str.val,argv[3]->value.str.len);
+       }
+
+       /* Create identifier string for connection */
+       sprintf(buffer, "%d", port);
+       hashed_details_length = strlen(host)+strlen(buffer)+8;
+       if(NULL == (hashed_details = (char *) emalloc(hashed_details_length+1))) {
+               if(host) efree(host);
+               if(password) efree(password);
+               if(username) efree(username);
+               php3_error(E_ERROR, "Could not get memory for connection details");
+               RETURN_FALSE;
+       }
+       sprintf(hashed_details,"hw_%s_%d",host,port);
+
+       if (persistent) {
+               list_entry *le;
+
+               /* try to find if we already have this link in our persistent list */
+               if (_php3_hash_find(plist, hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) {
+                       list_entry new_le;
+
+                       if (php3_hw_module.max_links!=-1 && php3_hw_module.num_links>=php3_hw_module.max_links) {
+                               php3_error(E_ERROR,"Hyperwave:  Too many open links (%d)",php3_hw_module.num_links);
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                       }
+                       if (php3_hw_module.max_persistent!=-1 && php3_hw_module.num_persistent>=php3_hw_module.max_persistent) {
+                               php3_error(E_ERROR,"Hyperwave: Too many open persistent links (%d)",php3_hw_module.num_persistent);
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                       }
+
+                       if ( (sockfd = open_hg_connection(host, port)) < 0 )  {
+                               php3_error(E_ERROR, "Could not open connection to %s, Port: %d (retval=%d)", host, port, sockfd);
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                               }
+       
+                       if(NULL == (ptr = malloc(sizeof(hw_connection)))) {
+                               php3_error(E_ERROR, "Could not get memory for connection structure");
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                       }
+       
+                       if(0 != (ptr->lasterror = initialize_hg_connection(sockfd, &do_swap, &version, &userdata, &server_string, username, password))) {
+                               php3_error(E_ERROR, "Could not initalize hyperwave connection");
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               if(userdata) efree(userdata);
+                               if(server_string) free(server_string);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                               }
+
+                       if(username) efree(username);
+                       if(password) efree(password);
+       
+                       ptr->version = version;
+                       ptr->server_string = server_string;
+                       ptr->socket = sockfd;
+                       ptr->swap_on = do_swap;
+                       ptr->linkroot = 0;
+                       ptr->hostname = strdup(host);
+                       ptr->username = strdup("anonymous");
+       
+                       new_le.ptr = (void *) ptr;
+                       new_le.type = php3_hw_module.le_psocketp;;
+
+                       if (_php3_hash_update(plist,hashed_details,hashed_details_length+1,(void *) &new_le, sizeof(list_entry), NULL)==FAILURE) {
+                               php3_error(E_ERROR, "Could not hash table with connection details");
+                               if(host) efree(host);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                               if(server_string) free(server_string);
+                               efree(hashed_details);
+                               RETURN_FALSE;
+                       }
+
+                       php3_hw_module.num_links++;
+                       php3_hw_module.num_persistent++;
+               } else {
+                       /*php3_printf("Found already open connection\n"); */
+                       if (le->type != php3_hw_module.le_psocketp) {
+                               RETURN_FALSE;
+                       }
+                       ptr = le->ptr;
+               }
+
+               return_value->value.lval = php3_list_insert(ptr,php3_hw_module.le_psocketp);
+               return_value->type = IS_LONG;
+       
+       } else {
+               list_entry *index_ptr,new_index_ptr;
+
+               /* first we check the hash for the hashed_details key.  if it exists,
+                * it should point us to the right offset where the actual hyperwave link sits.
+                * if it doesn't, open a new hyperwave link, add it to the resource list,
+                * and add a pointer to it with hashed_details as the key.
+                */
+               if (_php3_hash_find(list,hashed_details,hashed_details_length+1,(void **) &index_ptr)==SUCCESS) {
+                       int type,link;
+                       void *ptr;
+       
+                       if (index_ptr->type != le_index_ptr) {
+                               RETURN_FALSE;
+                       }
+                       link = (int) index_ptr->ptr;
+                       ptr = (hw_connection *) php3_list_find(link,&type);   /* check if the link is still there */
+                       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+                               return_value->value.lval = php3_hw_module.default_link = link;
+                               return_value->type = IS_LONG;
+                               efree(hashed_details);
+                               if(username) efree(username);
+                               if(password) efree(password);
+                       if(host) efree(host);
+                               return;
+                       } else {
+                               _php3_hash_del(list,hashed_details,hashed_details_length+1);
+                       }
+               }
+       
+               if ( (sockfd = open_hg_connection(host, port)) < 0 )  {
+                       php3_error(E_ERROR, "Could not open connection to %s, Port: %d (retval=%d", host, port, sockfd);
+                 if(host) efree(host);
+                       if(username) efree(username);
+                       if(password) efree(password);
+                       efree(hashed_details);
+                       RETURN_FALSE;
+                       }
+       
+               if(NULL == (ptr = malloc(sizeof(hw_connection)))) {
+                       if(host) efree(host);
+                       if(username) efree(username);
+                       if(password) efree(password);
+                       efree(hashed_details);
+                       RETURN_FALSE;
+               }
+       
+               if(0 != (ptr->lasterror = initialize_hg_connection(sockfd, &do_swap, &version, &userdata, &server_string, username, password))) {
+                       php3_error(E_ERROR, "Could not initalize hyperwave connection");
+                       if(host) efree(host);
+                       if(username) efree(username);
+                       if(password) efree(password);
+                       if(userdata) efree(userdata);
+                       if(server_string) free(server_string);
+                       efree(hashed_details);
+                       RETURN_FALSE;
+                       }
+
+               if(username) efree(username);
+               if(password) efree(password);
+       
+               ptr->version = version;
+               ptr->server_string = server_string;
+               ptr->socket = sockfd;
+               ptr->swap_on = do_swap;
+               ptr->linkroot = 0;
+               ptr->hostname = strdup(host);
+               ptr->username = strdup("anonymous");
+       
+               return_value->value.lval = php3_list_insert(ptr,php3_hw_module.le_socketp);
+               return_value->type = IS_LONG;
+       
+               new_index_ptr.ptr = (void *) return_value->value.lval;
+               new_index_ptr.type = le_index_ptr;
+               if (_php3_hash_update(list,hashed_details,hashed_details_length+1,(void *) &new_index_ptr, sizeof(list_entry), NULL)==FAILURE) {
+                       php3_error(E_ERROR, "Could not update connection details in hash table");
+                       if(host) efree(host);
+                       efree(hashed_details);
+                       RETURN_FALSE;
+               }
+       
+       }
+
+       efree(hashed_details);
+       if(host) efree(host);
+       php3_hw_module.default_link=return_value->value.lval;
+
+       /* At this point we have a working connection. If userdata was given
+          we are also indentified.
+          If there is no userdata because hw_connect was called without username
+          and password, we don't evaluate userdata.
+       */
+       if(NULL == userdata)
+               return;
+
+       if(ptr->username) free(ptr->username);
+       str = userdata;
+       while((*str != 0) && (*str != ' '))
+               str++;
+       if(*str != '\0')
+               ptr->username = strdup(++str);
+       else
+               ptr->username = NULL;
+       efree(userdata);
+}
+
+/* Start of user level functions */
+/* ***************************** */
+/* {{{ proto int hw_connect(string host, int port [string username [, string password]])
+   Connect to the Hyperwave server */
+void php3_hw_connect(INTERNAL_FUNCTION_PARAMETERS)
+{
+       php3_hw_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
+}
+/* }}} */
+
+/* {{{ proto int hw_pconnect(string host, int port [string username [, string password]])
+   Connect to the Hyperwave server persistent */
+void php3_hw_pconnect(INTERNAL_FUNCTION_PARAMETERS)
+{
+       php3_hw_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
+}
+/* }}} */
+
+/* {{{ proto void hw_close(int link)
+   Close connection to Hyperwave server */
+void php3_hw_close(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+       php3_list_delete(id);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto void hw_info(int link)
+   Outputs info string */
+void php3_hw_info(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *arg1;
+       int id, type;
+       hw_connection *ptr;
+       char *str;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+       if(NULL != (str = get_hw_info(ptr))) {
+               /*
+               php3_printf("%s\n", str);
+               efree(str);
+               */
+               return_value->value.str.len = strlen(str);
+               return_value->value.str.val = str;
+               return_value->type = IS_STRING;
+               return;
+               }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int hw_error(int link)
+   Returns last error number */
+void php3_hw_error(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *arg1;
+       int id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+       RETURN_LONG(ptr->lasterror);
+}
+/* }}} */
+
+/* {{{ proto string hw_errormsg(int link)
+   Returns last error message */
+void php3_hw_errormsg(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *arg1;
+       int id, type;
+       hw_connection *ptr;
+       char errstr[100];
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       switch(ptr->lasterror) {
+               case 0:
+                       sprintf(errstr, "No error");
+                       break;
+               case NOACCESS:
+                       sprintf(errstr, "No access");
+                       break;
+               case NODOCS:
+                       sprintf(errstr, "No documents");
+                       break;
+               case NONAME:
+                       sprintf(errstr, "No collection name");
+                       break;
+               case NODOC:
+                       sprintf(errstr, "Object is not a document");
+                       break;
+               case NOOBJ:
+                       sprintf(errstr, "No object received");
+                       break;
+               case NOCOLLS:
+                       sprintf(errstr, "No collections received");
+                       break;
+               case DBSTUBNG:
+                       sprintf(errstr, "Connection to low-level database failed");
+                       break;
+               case NOTFOUND:
+                       sprintf(errstr, "Object not found");
+                       break;
+               case EXIST:
+                       sprintf(errstr, "Collection already exists");
+                       break;
+               case FATHERDEL:
+                       sprintf(errstr, "parent collection disappeared");
+                       break;
+               case FATHNOCOLL:
+                       sprintf(errstr, "parent collection not a collection");
+                       break;
+               case NOTEMPTY:
+                       sprintf(errstr, "Collection not empty");
+                       break;
+               case DESTNOCOLL:
+                       sprintf(errstr, "Destination not a collection");
+                       break;
+               case SRCEQDEST:
+                       sprintf(errstr, "Source equals destination");
+                       break;
+               case REQPEND:
+                       sprintf(errstr, "Request pending");
+                       break;
+               case TIMEOUT:
+                       sprintf(errstr, "Timeout");
+                       break;
+               case NAMENOTUNIQUE:
+                       sprintf(errstr, "Name not unique");
+                       break;
+               case WRITESTOPPED:
+                       sprintf(errstr, "Database now read-only; try again later");
+                       break;
+               case LOCKED:
+                       sprintf(errstr, "Object locked; try again later");
+                       break;
+               default:
+                       sprintf(errstr, "Unknown error: %d", ptr->lasterror);
+               }
+       RETURN_STRING(errstr, 1);
+}
+/* }}} */
+
+/* {{{ proto hw_root(void)
+   Returns object id of root collection */
+void php3_hw_root(INTERNAL_FUNCTION_PARAMETERS)
+{
+       TLS_VARS;
+       return_value->value.lval = 0;
+       return_value->type = IS_LONG;
+}
+/* }}} */
+
+char *php3_hw_command(INTERNAL_FUNCTION_PARAMETERS, int comm) {
+       pval *arg1;
+       int link, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               return NULL;
+       }
+       convert_to_long(arg1);
+       link=arg1->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               return NULL;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       if (0 != (ptr->lasterror = send_command(ptr->socket, comm, &object)))
+               return NULL;
+
+       return object;
+       }
+}
+
+/* {{{ proto string hw_stat(int link)
+   Returns status string */
+void php3_hw_stat(INTERNAL_FUNCTION_PARAMETERS) {
+        char *object;
+
+       object = php3_hw_command(INTERNAL_FUNCTION_PARAM_PASSTHRU, STAT_COMMAND);
+       if(object == NULL)
+               RETURN_FALSE;
+
+       return_value->value.str.val = object;
+       return_value->value.str.len = strlen(object);
+       return_value->type = IS_STRING;
+}
+/* }}} */
+
+/* {{{ proto array hw_who(int link)
+   Returns names and info of users loged in */
+void php3_hw_who(INTERNAL_FUNCTION_PARAMETERS) {
+       pval user_arr;
+        char *object, *ptr, *temp, *attrname;
+       int i;
+
+       object = php3_hw_command(INTERNAL_FUNCTION_PARAM_PASSTHRU, WHO_COMMAND);
+       if(object == NULL)
+               RETURN_FALSE;
+
+       ptr = object;
+
+        while((*ptr != '\0') && (*ptr != '\n'))
+               ptr++;
+        while((*ptr != '\0') && (*ptr != '\n'))
+               ptr++;
+       if(*ptr == '\0') {
+               efree(object);
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(object);
+               RETURN_FALSE;
+       }
+
+       temp = estrdup(ptr);
+       attrname = strtok(temp, "\n");
+       i = 0;
+       while(attrname != NULL) {
+               char *name;
+
+               if (array_init(&user_arr) == FAILURE) {
+                       efree(object);
+                       RETURN_FALSE;
+               }
+
+               ptr = attrname;
+               if(*ptr == '*')
+                       add_assoc_long(&user_arr, "self", 1);
+               else
+                       add_assoc_long(&user_arr, "self", 0);
+                       
+               ptr++;
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "id", name, 1);
+
+               ptr++;
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "name", name, 1);
+
+               ptr++;
+               while((*ptr != '\0') && (*ptr == ' '))
+                       ptr++;
+
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "system", name, 1);
+
+               ptr++;
+               while((*ptr != '\0') && (*ptr == ' '))
+                       ptr++;
+
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "onSinceDate", name, 1);
+
+               ptr++;
+               while((*ptr != '\0') && (*ptr == ' '))
+                       ptr++;
+
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "onSinceTime", name, 1);
+
+               ptr++;
+               while((*ptr != '\0') && (*ptr == ' '))
+                       ptr++;
+
+               name = ptr;
+               while((*ptr != '\0') && (*ptr != ' '))
+                       ptr++;
+               *ptr = '\0';
+               add_assoc_string(&user_arr, "TotalTime", name, 1);
+
+               /* Add the user array */
+               _php3_hash_index_update(return_value->value.ht, i++, &user_arr, sizeof(pval), NULL);
+
+               /* The user array can now be freed, but I don't know how */
+
+               attrname = strtok(NULL, "\n");
+       }
+       efree(temp);
+       efree(object);
+
+}
+/* }}} */
+
+void php3_hw_dummy(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, id, type, msgid;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_long(arg3);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       msgid=arg3->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       if (0 != (ptr->lasterror = send_dummy(ptr->socket, id, msgid, &object)))
+               RETURN_FALSE;
+
+php3_printf("%s", object);
+       return_value->value.str.val = object;
+       return_value->value.str.len = strlen(object);
+       return_value->type = IS_STRING;
+       }
+}
+
+/* {{{ proto string hw_getobject(int link, int objid)
+   Returns object record  */
+void php3_hw_getobject(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       if (0 != (ptr->lasterror = send_getobject(ptr->socket, id, &object)))
+               RETURN_FALSE;
+
+       RETURN_STRING(object, 0);
+       /*
+       make_return_array_from_objrec(&return_value, object);
+       efree(object);
+       */
+       }
+}
+/* }}} */
+
+/* {{{ proto int hw_insertobject(int link, string objrec, string parms)
+   Inserts an object */
+void php3_hw_insertobject(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, type;
+       char *objrec, *parms;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_string(arg3);
+       link=arg1->value.lval;
+       objrec=arg2->value.str.val;
+       parms=arg3->value.str.val;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       int objid;
+       if (0 != (ptr->lasterror = send_insertobject(ptr->socket, objrec, parms, &objid)))
+               RETURN_FALSE;
+
+       RETURN_LONG(objid);
+       }
+}
+/* }}} */
+
+/* {{{ proto string hw_getandlock(int link, int objid)
+   Returns object record and locks object */
+void php3_hw_getandlock(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attrname, *str;
+       if (0 != (ptr->lasterror = send_getandlock(ptr->socket, id, &object)))
+               RETURN_FALSE;
+
+       RETURN_STRING(object, 0);
+       }
+}
+/* }}} */
+
+/* {{{ proto void hw_unlock(int link, int objid)
+   Unlocks object */
+void php3_hw_unlock(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_unlock(ptr->socket, id)))
+               RETURN_FALSE;
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto void hw_deleteobject(int link, int objid)
+   Deletes object */
+void php3_hw_deleteobject(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_deleteobject(ptr->socket, id)))
+               RETURN_FALSE;
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto void hw_changeobject(int link, int objid, array attributes)
+   Changes attributes of an object */
+void php3_hw_changeobject(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, id, type, i;
+       hw_connection *ptr;
+       char *modification, *oldobjrec, buf[200];
+       HashTable *newobjarr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1); /* Connection */
+       convert_to_long(arg2); /* object ID */
+       convert_to_array(arg3); /* Array with new attributes */
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       newobjarr=arg3->value.ht;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       /* get the old object record */
+       if(0 != (ptr->lasterror = send_getobject(ptr->socket, id, &oldobjrec)))
+               RETURN_FALSE;
+
+       _php3_hash_internal_pointer_reset(newobjarr);
+       modification = strdup("");
+       for(i=0; i<_php3_hash_num_elements(newobjarr); i++) {
+               char *key, *str, *str1, newattribute[200];
+               pval *data;
+               int j, noinsert=1;
+               ulong ind;
+
+               _php3_hash_get_current_key(newobjarr, &key, &ind);
+               _php3_hash_get_current_data(newobjarr, (void *) &data);
+               switch(data->type) {
+                       case IS_STRING:
+                               if(strlen(data->value.str.val) == 0)
+                                       noinsert = 0;
+                               else
+                                       sprintf(newattribute, "%s=%s", key, data->value.str.val);
+                               break;
+                       default:
+                               sprintf(newattribute, "%s", "");
+               }
+
+               if(!noinsert) {
+                       modification = fnInsStr(modification, 0, "\\");
+                       modification = fnInsStr(modification, 0, newattribute);
+                       modification = fnInsStr(modification, 0, "add ");
+
+                       /* Retrieve the old attribute from object record */
+                       if(NULL != (str = strstr(oldobjrec, key))) {
+                               str1 = str;
+                               j = 0;
+                               while((str1 != NULL) && (*str1 != '\n')) {
+                                       buf[j++] = *str1++;
+                               }
+                               buf[j] = '\0';
+                               modification = fnInsStr(modification, 0, "\\");
+                               modification = fnInsStr(modification, 0, buf);
+                               modification = fnInsStr(modification, 0, "rem ");
+                       } 
+               }
+               efree(key);
+               _php3_hash_move_forward(newobjarr);
+       }
+       efree(oldobjrec);
+
+       set_swap(ptr->swap_on);
+       modification[strlen(modification)-1] = '\0';
+/*     php3_printf("0x%X, %s", id, modification); */
+       if (0 != (ptr->lasterror = send_changeobject(ptr->socket, id, modification)))
+               RETURN_FALSE;
+       free(modification);
+       RETURN_TRUE;
+}
+/* }}} */
+
+void php3_hw_mvcp(INTERNAL_FUNCTION_PARAMETERS, int mvcp) {
+       pval *arg1, *arg2, *arg3, *arg4, **objvIDs;
+       int link, type, dest=0, from=0;
+       HashTable *src_arr;
+       hw_connection *ptr;
+       int collIDcount, docIDcount, i, *docIDs, *collIDs;
+       TLS_VARS;
+
+       switch(mvcp) {
+               case MOVE: /* Move also has fromID */
+                       if (ARG_COUNT(ht) != 4 || getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE)
+                               WRONG_PARAM_COUNT;
+                       break;
+               case COPY:
+                       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE)
+                               WRONG_PARAM_COUNT;
+                       break;
+       }
+       convert_to_long(arg1);
+       convert_to_array(arg2);
+       convert_to_long(arg3);
+       link=arg1->value.lval;
+       src_arr=arg2->value.ht;
+       switch(mvcp) {
+               case MOVE: /* Move also has fromID, which is arg3 --> arg4 becomes destID */
+                       convert_to_long(arg4);
+                       from=arg3->value.lval;
+                       dest=arg4->value.lval;
+                       break;
+               case COPY: /* No fromID for Copy needed --> arg3 is destID */
+                       dest=arg3->value.lval;
+                       from = 0;
+                       break;
+       }
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+
+       if(NULL == (objvIDs = emalloc(_php3_hash_num_elements(src_arr) * sizeof(pval *)))) {
+               RETURN_FALSE;
+               }
+
+       if(getParametersArray(src_arr, _php3_hash_num_elements(src_arr), objvIDs) == FAILURE) {
+               RETURN_FALSE;
+               }
+
+       if(NULL == (collIDs = emalloc(_php3_hash_num_elements(src_arr) * sizeof(int)))) {
+               efree(objvIDs);
+               RETURN_FALSE;
+               }
+
+       if(NULL == (docIDs = emalloc(_php3_hash_num_elements(src_arr) * sizeof(int)))) {
+               efree(objvIDs);
+               efree(collIDs);
+               RETURN_FALSE;
+               }
+
+       collIDcount = docIDcount = 0;
+       for(i=0; i<_php3_hash_num_elements(src_arr); i++) {
+               char *objrec;
+               if(objvIDs[i]->type == IS_LONG) {
+                       if(0 != (ptr->lasterror = send_getobject(ptr->socket, objvIDs[i]->value.lval, &objrec))) {
+                               efree(objvIDs);
+                               efree(collIDs);
+                               efree(docIDs);
+                               RETURN_FALSE;
+                       }
+                       if(0 == fnAttributeCompare(objrec, "DocumentType", "collection"))
+                               collIDs[collIDcount++] = objvIDs[i]->value.lval;
+                       else
+                               docIDs[docIDcount++] = objvIDs[i]->value.lval;
+                       efree(objrec);
+               }
+       }
+       efree(objvIDs);
+
+       if (0 != (ptr->lasterror = send_mvcpdocscoll(ptr->socket, docIDs, docIDcount, from, dest, mvcp))) {
+               efree(collIDs);
+               efree(docIDs);
+               RETURN_FALSE;
+       }
+
+       if (0 != (ptr->lasterror = send_mvcpcollscoll(ptr->socket, collIDs, collIDcount, from, dest, mvcp))) {
+               efree(collIDs);
+               efree(docIDs);
+               RETURN_FALSE;
+       }
+
+       efree(collIDs);
+       efree(docIDs);
+
+       RETURN_LONG(docIDcount + collIDcount);
+}
+
+/* {{{ proto void hw_mv(int link, array objrec, int from, int dest)
+   Moves object */
+void php3_hw_mv(INTERNAL_FUNCTION_PARAMETERS) {
+       php3_hw_mvcp(INTERNAL_FUNCTION_PARAM_PASSTHRU, MOVE);
+}
+/* }}} */
+
+/* {{{ proto void hw_cp(int link, array objrec, int dest)
+   Copies object */
+void php3_hw_cp(INTERNAL_FUNCTION_PARAMETERS) {
+       php3_hw_mvcp(INTERNAL_FUNCTION_PARAM_PASSTHRU, COPY);
+}
+/* }}} */
+
+/* {{{ proto hwdoc hw_gettext(int link, int objid[, int rootid])
+   Returns text document. Links are relative to rootid if given */
+void php3_hw_gettext(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *argv[3];
+       int argc, link, id, type, mode;
+       int rootid = 0;
+       hw_document *doc;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       argc = ARG_COUNT(ht);
+       if((argc > 3) || (argc < 2))
+               WRONG_PARAM_COUNT;
+               
+       if (getParametersArray(ht, argc, argv) == FAILURE)
+               RETURN_FALSE;
+
+       convert_to_long(argv[0]);
+       convert_to_long(argv[1]);
+       if(argc == 3) {
+               convert_to_long(argv[2]);
+               rootid = argv[2]->value.lval;
+               mode = 1;
+       } else
+               mode = 0;
+       link=argv[0]->value.lval;
+       id=argv[1]->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attributes = NULL;
+       char *bodytag = NULL;
+       int count;
+       /* !!!! memory for object and attributes is allocated with malloc !!!! */
+       if (0 != (ptr->lasterror = send_gettext(ptr->socket, id, mode, rootid, &attributes, &bodytag, &object, &count)))
+               RETURN_FALSE;
+       doc = malloc(sizeof(hw_document));
+       doc->data = object;
+       doc->attributes = attributes;
+       doc->bodytag = bodytag;
+       doc->size = count;
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+       }
+}
+/* }}} */
+
+/* {{{ proto void hw_edittext(int link, hwdoc doc)
+   Modifies text document */
+void php3_hw_edittext(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, doc, type;
+       hw_connection *ptr;
+       hw_document *docptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       ptr = php3_list_find(link,&type);
+
+       /* FIXME id is not set anywhere */
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       doc=arg2->value.lval;
+       docptr = php3_list_find(doc,&type);
+
+       /* FIXME id is not set anywhere */
+       if(!docptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       if (0 != (ptr->lasterror =  send_edittext(ptr->socket, docptr->attributes, docptr->data))) {
+               RETURN_FALSE;
+               }
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto hwdoc hw_getcgi(int link, int objid)
+   Returns the output of a cgi script */
+void php3_hw_getcgi(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_document *doc;
+       hw_connection *ptr;
+       char cgi_env_str[1000];
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attributes = NULL;
+       int count;
+
+       /* Here is another undocument function of Hyperwave.
+          If you call a cgi script with getcgi-message, you will
+          have to provide the complete cgi enviroment, since it is
+          only known to the webserver (or wavemaster). This is done
+          by extending the object record with the following incomplete
+          string. It should contain any enviroment variable a cgi script
+          requires.
+       */
+#if (WIN32|WINNT)
+       sprintf(cgi_env_str, "CGI_REQUEST_METHOD=%s\nCGI_PATH_INFO=%s\nCGI_QUERY_STRING=%s",
+                            getenv("REQUEST_METHOD"),
+                            getenv("PATH_INFO"),
+                            getenv("QUERY_STRING"));
+#else
+       sprintf(cgi_env_str, "CGI_REQUEST_METHOD=%s\nCGI_PATH_INFO=%s\nCGI_QUERY_STRING=%s",
+                            GLOBAL(request_info).request_method,
+                            GLOBAL(request_info).path_info,
+                            GLOBAL(request_info).query_string);
+#endif
+       /* !!!! memory for object and attributes is allocated with malloc !!!! */
+       if (0 != (ptr->lasterror = send_getcgi(ptr->socket, id, cgi_env_str, &attributes, &object, &count)))
+               RETURN_FALSE;
+       doc = malloc(sizeof(hw_document));
+       doc->data = object;
+       doc->attributes = attributes;
+       doc->bodytag = NULL;
+       doc->size = count;
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+       }
+}
+/* }}} */
+
+/* {{{ proto hwdoc hw_getremote(int link, int objid)
+   Returns the output of a remote document */
+void php3_hw_getremote(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_document *doc;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attributes = NULL;
+       int count;
+       /* !!!! memory for object and attributes is allocated with malloc !!!! */
+       if (0 != (ptr->lasterror = send_getremote(ptr->socket, id, &attributes, &object, &count)))
+               RETURN_FALSE;
+       doc = malloc(sizeof(hw_document));
+       doc->data = object;
+       doc->attributes = attributes;
+       doc->bodytag = NULL;
+       doc->size = count;
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+       }
+}
+/* }}} */
+
+/* {{{ proto [array|hwdoc] hw_getremotechildren(int link, int objid)
+   Returns the remote document if only one or an array of object records */
+void php3_hw_getremotechildren(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, type, i;
+       hw_connection *ptr;
+       char *objrec;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       link=arg1->value.lval;
+       objrec=arg2->value.str.val;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d", link);
+               RETURN_FALSE;
+       }
+       set_swap(ptr->swap_on);
+       {
+       int count, *offsets;
+       char *remainder, *ptr1;
+       if (0 != (ptr->lasterror = send_getremotechildren(ptr->socket, objrec, &remainder, &offsets, &count)))
+               RETURN_FALSE;
+
+       if(strncmp(remainder, "ObjectID=0 ", 10)) {
+               hw_document *doc;
+               remainder[offsets[0]-18] = '\0';
+/*php3_printf("offset = %d, remainder = %s---", offsets[0], remainder);*/
+               doc = malloc(sizeof(hw_document));
+               doc->data = strdup(remainder);
+               doc->attributes = strdup(objrec);
+               doc->bodytag = NULL;
+               doc->size = offsets[0]-18;
+               return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+               return_value->type = IS_LONG;
+       } else {
+               if (array_init(return_value) == FAILURE) {
+                       efree(offsets);
+                       RETURN_FALSE;
+               }
+
+               ptr1 = remainder;
+               for(i=0; i<count; i++) {
+                       *(ptr1+offsets[i]-1) = '\0';
+                       add_index_string(return_value, i, ptr1, 1);
+                       ptr1 += offsets[i];
+               }
+       }
+
+       efree(offsets);
+       efree(remainder);
+       }
+}
+/* }}} */
+
+/* {{{ proto void hw_setlinkroot(int link, int rootid)
+   Set the id to which links are calculated */
+void php3_hw_setlinkroot(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, type, rootid;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link = arg1->value.lval;
+       rootid = arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       ptr->linkroot = rootid;
+       RETURN_LONG(rootid);
+}
+/* }}} */
+
+/* {{{ proto hwdoc hw_pipedocument(int link, int objid)
+   Returns document */
+void php3_hw_pipedocument(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *argv[3];
+       int link, id, type, argc, mode;
+       int rootid = 0;
+       hw_connection *ptr;
+       hw_document *doc;
+#if APACHE
+       server_rec *serv = GLOBAL(php3_rqst)->server;
+#endif
+       TLS_VARS;
+
+       argc = ARG_COUNT(ht);
+       if((argc > 2) || (argc < 2))
+               WRONG_PARAM_COUNT;
+               
+       if (getParametersArray(ht, argc, argv) == FAILURE)
+               RETURN_FALSE;
+
+       convert_to_long(argv[0]);
+       convert_to_long(argv[1]);
+/*     if(argc == 3) {
+               convert_to_long(argv[2]);
+               rootid = argv[2]->value.lval;
+               if(rootid != 0)
+                       mode = 1;
+       }
+*/     link=argv[0]->value.lval;
+       id=argv[1]->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d", link);
+               RETURN_FALSE;
+       }
+
+       mode = 0;
+       if(ptr->linkroot > 0)
+               mode = 1;
+       rootid = ptr->linkroot;
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attributes = NULL;
+       char *bodytag = NULL;
+       int count;
+       /* !!!! memory for object, bodytag and attributes is allocated with malloc !!!! */
+       if (0 != (ptr->lasterror =  send_pipedocument(ptr->socket,
+#if APACHE
+  serv->server_hostname,
+#else
+  getenv("HOST"),
+#endif
+   id, mode, rootid, &attributes, &bodytag, &object, &count)))
+               RETURN_FALSE;
+
+       doc = malloc(sizeof(hw_document));
+       doc->data = object;
+       doc->attributes = attributes;
+       doc->bodytag = bodytag;
+       doc->size = count;
+fprintf(stderr, "size = %d\n", count);
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+       }
+}  /* }}} */
+
+/* {{{ proto hwdoc hw_pipecgi(int link, int objid)
+   Returns output of cgi script */
+void php3_hw_pipecgi(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       hw_document *doc;
+       char cgi_env_str[1000];
+#if APACHE
+       server_rec *serv = GLOBAL(php3_rqst)->server;
+#endif
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       char *attributes = NULL;
+       int count;
+
+#if (WIN32|WINNT)
+       sprintf(cgi_env_str, "CGI_REQUEST_METHOD=%s\nCGI_PATH_INFO=%s\nCGI_QUERY_STRING=%s",
+                            getenv("REQUEST_METHOD"),
+                            getenv("PATH_INFO"),
+                            getenv("QUERY_STRING"));
+#else
+       sprintf(cgi_env_str, "CGI_REQUEST_METHOD=%s\nCGI_PATH_INFO=%s\nCGI_QUERY_STRING=%s",
+                            GLOBAL(request_info).request_method,
+                            GLOBAL(request_info).path_info,
+                            GLOBAL(request_info).query_string);
+#endif
+       /* !!!! memory for object, bodytag and attributes is allocated with malloc !!!! */
+       if (0 != (ptr->lasterror =  send_pipecgi(ptr->socket,
+#if APACHE
+  serv->server_hostname,
+#else
+  getenv("HOST"),
+#endif
+  id, cgi_env_str, &attributes, &object, &count)))
+               RETURN_FALSE;
+
+       doc = malloc(sizeof(hw_document));
+       doc->data = object;
+       doc->attributes = attributes;
+       doc->bodytag = NULL;
+       doc->size = count;
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+       }
+}  /* }}} */
+
+/* {{{ proto void hw_insertdocument(int link, int parentid, hwdoc doc) 
+   Insert new document */
+void php3_hw_insertdocument(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, id, doc, type;
+       hw_connection *ptr;
+       hw_document *docptr;
+#if APACHE
+       server_rec *serv = GLOBAL(php3_rqst)->server;
+#endif
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_long(arg3);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find connection identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       doc=arg3->value.lval;
+       docptr = php3_list_find(doc,&type);
+       if(!docptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find document identifier %d",doc);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       if (0 != (ptr->lasterror =  send_putdocument(ptr->socket,
+#if APACHE
+  serv->server_hostname,
+#else
+  getenv("HOST"),
+#endif
+             id, docptr->attributes, docptr->data, docptr->size))) {
+               RETURN_FALSE;
+               }
+       }
+       RETURN_TRUE;
+}  /* }}} */
+
+/* {{{ proto hwdoc hw_new_document(int link, string data, string objrec, int size)
+   Create a new document */
+void php3_hw_new_document(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       hw_document *doc;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_string(arg1);
+       convert_to_string(arg2);
+       convert_to_long(arg3);
+
+       doc = malloc(sizeof(hw_document));
+       doc->data = malloc(arg3->value.lval);
+        memcpy(doc->data, arg2->value.str.val, arg3->value.lval);
+       doc->attributes = strdup(arg1->value.str.val);
+       doc->bodytag = NULL;
+       doc->size = arg3->value.lval;
+       return_value->value.lval = php3_list_insert(doc,php3_hw_module.le_document);
+       return_value->type = IS_LONG;
+}  /* }}} */
+
+/* {{{ proto void hw_free_document(hwdoc doc)
+   Frees memory of document */
+void php3_hw_free_document(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int id, type;
+       hw_document *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+       php3_list_delete(id);
+       RETURN_TRUE;
+}  /* }}} */
+
+/* {{{ proto void hw_output_document(hwdoc doc)
+   Prints document */
+void php3_hw_output_document(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int id, type, count;
+       hw_document *ptr;
+       char *ptr1;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       ptr1 = ptr->data;
+       count = 0;
+       while(count < ptr->size) {
+               php3_write(ptr1++, 1);
+               count++;
+       }
+
+       RETURN_TRUE;
+}  /* }}} */
+
+/* {{{ proto string hw_document_bodytag(hwdoc doc [, string prefix])
+   Return bodytag prefixed by prefix */
+void php3_hw_document_bodytag(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *argv[2];
+       int id, type, argc;
+       hw_document *ptr;
+       char *temp, *str = NULL;
+       TLS_VARS;
+
+       argc = ARG_COUNT(ht);
+       if((argc > 2) || (argc < 1))
+               WRONG_PARAM_COUNT;
+               
+       if (getParametersArray(ht, argc, argv) == FAILURE)
+               RETURN_FALSE;
+       
+       convert_to_long(argv[0]);
+       id=argv[0]->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       if(argc == 2) {
+               convert_to_string(argv[1]);
+               str=argv[1]->value.str.val;
+       }
+
+       if(str != NULL) {
+               temp = emalloc(argv[1]->value.str.len + strlen(ptr->bodytag) + 2);
+               strcpy(temp, ptr->bodytag);
+               strcpy(temp+strlen(ptr->bodytag)-1, str);
+               strcpy(temp+strlen(ptr->bodytag)-1+argv[1]->value.str.len, ">\n");
+               RETURN_STRING(temp, 0);
+       } else {
+               RETURN_STRING(ptr->bodytag, 1);
+       }
+}  /* }}} */
+
+/* {{{ proto string hw_document_content(hwdoc doc)
+   Returns content of document */
+void php3_hw_document_content(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *argv[1];
+       int id, type, argc;
+       hw_document *ptr;
+       TLS_VARS;
+
+       argc = ARG_COUNT(ht);
+       if(argc != 1)
+               WRONG_PARAM_COUNT;
+               
+       if (getParametersArray(ht, argc, argv) == FAILURE)
+               RETURN_FALSE;
+       
+       convert_to_long(argv[0]);
+       id=argv[0]->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING(ptr->data, 1);
+}  /* }}} */
+
+/* {{{ proto int hw_document_content(hwdoc doc)
+   Returns size of document */
+void php3_hw_document_size(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int id, type;
+       hw_document *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       RETURN_LONG(ptr->size);
+}  /* }}} */
+
+/* {{{ proto string hw_document_content(hwdoc doc)
+   Returns object record of document */
+void php3_hw_document_attributes(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int id, type;
+       hw_document *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       id=arg1->value.lval;
+       ptr = php3_list_find(id,&type);
+       if(!ptr || (type!=php3_hw_module.le_document)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING(ptr->attributes, 1);
+/*     make_return_array_from_objrec(&return_value, ptr->attributes); */
+}  /* }}} */
+
+/* {{{ proto array hw_getparentsobj(int link, int objid)
+   Returns array of parent object records */
+void php3_hw_getparentsobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+
+       if (0 != (ptr->lasterror = send_getparentsobj(ptr->socket, id, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getparentsobj) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto array hw_getparents(int link, int objid)
+   Returns array of parent object ids */
+void php3_hw_getparents(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+        {
+       int  *childIDs = NULL;
+       int i;
+
+       if (0 != (ptr->lasterror = send_getparents(ptr->socket, id, &childIDs, &count))) {
+               php3_error(E_WARNING, "send_command (getparents) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++) {
+               add_index_long(return_value, i, childIDs[i]);
+       }
+       efree(childIDs);
+       }
+
+}  /* }}} */
+
+/* {{{ proto array hw_children(int link, int objid)
+   Returns array of children object ids */
+void php3_hw_children(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       int  *childIDs = NULL;
+       int i;
+
+       if (0 != (ptr->lasterror = send_children(ptr->socket, id, &childIDs, &count))){
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++) {
+               add_index_long(return_value, i, childIDs[i]);
+       }
+       efree(childIDs);
+       }
+               
+}  /* }}} */
+
+/* {{{ proto array hw_children(int link, int objid)
+   Returns array of children object records */
+void php3_hw_childrenobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+
+       if (0 != (ptr->lasterror = send_childrenobj(ptr->socket, id, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcollobj) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto array hw_childcoll(int link, int objid)
+   Returns array of child collection object ids */
+void php3_hw_getchildcoll(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       int  *childIDs = NULL;
+       int i;
+
+       if (0 != (ptr->lasterror = send_getchildcoll(ptr->socket, id, &childIDs, &count))){
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++) {
+               add_index_long(return_value, i, childIDs[i]);
+       }
+       efree(childIDs);
+       }
+               
+}  /* }}} */
+
+/* {{{ proto array hw_childcollobj(int link, int objid)
+   Returns array of child collection object records */
+void php3_hw_getchildcollobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+
+       if (0 != (ptr->lasterror = send_getchildcollobj(ptr->socket, id, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcollobj) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto int hw_docbyanchor(int link, int anchorid)
+   Returns objid of document belonging to anchorid */
+void php3_hw_docbyanchor(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       int objectID;
+       if (0 != (ptr->lasterror = send_docbyanchor(ptr->socket, id, &objectID)))
+               RETURN_FALSE;
+
+       RETURN_LONG(objectID);
+       }
+}  /* }}} */
+
+/* {{{ proto array hw_docbyanchorobj(int link, int anchorid)
+   Returns object record of document belonging to anchorid */
+void php3_hw_docbyanchorobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *object = NULL;
+       if (0 != (ptr->lasterror = send_docbyanchorobj(ptr->socket, id, &object)))
+               RETURN_FALSE;
+
+       RETURN_STRING(object, 0);
+       /*
+       make_return_array_from_objrec(&return_value, object);
+       efree(object);
+       */
+       }
+}  /* }}} */
+
+/* {{{ proto array hw_getobjectbyquery(int link, string query, int maxhits)
+   Search for query and return maxhits objids */
+void php3_hw_getobjectbyquery(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, type, maxhits;
+       char *query;
+       int count, i;
+       int  *childIDs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_long(arg3);
+       link=arg1->value.lval;
+       query=arg2->value.str.val;
+       maxhits=arg3->value.lval;
+       if (maxhits < 0) maxhits=0x7FFFFFFF;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getobjbyquery(ptr->socket, query, maxhits, &childIDs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++)
+               add_index_long(return_value, i, childIDs[i]);
+       efree(childIDs);
+}  /* }}} */
+
+/* {{{ proto array hw_getobjectbyqueryobj(int link, string query, int maxhits)
+   Search for query and return maxhits object records */
+void php3_hw_getobjectbyqueryobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, type, maxhits;
+       char *query;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_long(arg3);
+       link=arg1->value.lval;
+       query=arg2->value.str.val;
+       maxhits=arg3->value.lval;
+       if (maxhits < 0) maxhits=0x7FFFFFFF;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getobjbyqueryobj(ptr->socket, query, maxhits, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto array hw_getobjectbyquerycoll(int link, int collid, string query, int maxhits)
+   Search for query in collection and return maxhits objids */
+void php3_hw_getobjectbyquerycoll(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3, *arg4;
+       int link, id, type, maxhits;
+       char *query;
+       int count, i;
+       hw_connection *ptr;
+       int  *childIDs = NULL;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 4 || getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_string(arg3);
+       convert_to_long(arg4);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       query=arg3->value.str.val;
+       maxhits=arg4->value.lval;
+       if (maxhits < 0) maxhits=0x7FFFFFFF;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getobjbyquerycoll(ptr->socket, id, query, maxhits, &childIDs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++)
+               add_index_long(return_value, i, childIDs[i]);
+       efree(childIDs);
+}  /* }}} */
+
+/* {{{ proto array hw_getobjectbyquerycollobj(int link, int collid, string query, int maxhits)
+   Search for query in collection and return maxhits object records */
+void php3_hw_getobjectbyquerycollobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3, *arg4;
+       int link, id, type, maxhits;
+       char *query;
+       int count;
+       hw_connection *ptr;
+       char  **childObjRecs = NULL;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 4 || getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_string(arg3);
+       convert_to_long(arg4);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       query=arg3->value.str.val;
+       maxhits=arg4->value.lval;
+       if (maxhits < 0) maxhits=0x7FFFFFFF;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getobjbyquerycollobj(ptr->socket, id, query, maxhits, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getchildcoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto array hw_getchilddoccoll(int link, int objid)
+   Returns all children ids which are documents */
+void php3_hw_getchilddoccoll(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count, i;
+       int  *childIDs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getchilddoccoll(ptr->socket, id, &childIDs, &count))) {
+               php3_error(E_WARNING, "send_command (getchilddoccoll) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(childIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++)
+               add_index_long(return_value, i, childIDs[i]);
+       efree(childIDs);
+}  /* }}} */
+
+/* {{{ proto array hw_getchilddoccollobj(int link, int objid)
+   Returns all children object records which are documents */
+void php3_hw_getchilddoccollobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getchilddoccollobj(ptr->socket, id, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getchilddoccollobj) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+
+}  /* }}} */
+
+/* {{{ proto array hw_getanchors(int link, int objid)
+   Return all anchors of object */
+void php3_hw_getanchors(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count, i;
+       int  *anchorIDs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getanchors(ptr->socket, id, &anchorIDs, &count))) {
+               php3_error(E_WARNING, "send_command (getanchors) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       if (array_init(return_value) == FAILURE) {
+               efree(anchorIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<count; i++)
+               add_index_long(return_value, i, anchorIDs[i]);
+       efree(anchorIDs);
+}  /* }}} */
+
+/* {{{ proto array hw_getanchorsobj(int link, int objid)
+   Return all object records of anchors of object */
+void php3_hw_getanchorsobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, id, type;
+       int count;
+       char  **anchorObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = (hw_connection *) php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",id);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getanchorsobj(ptr->socket, id, &anchorObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getanchors) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, anchorObjRecs, count))
+               RETURN_FALSE;
+}  /* }}} */
+
+/* {{{ proto string hw_getusername(int link)
+   Returns the current user name */
+void php3_hw_getusername(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       int link, type;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       link = arg1->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       return_value->value.str.val = estrdup(ptr->username);
+       return_value->value.str.len = strlen(ptr->username);
+       return_value->type = IS_STRING;
+}  /* }}} */
+
+
+/* {{{ proto void hw_identify(int link, string username, string password)
+   Identifies at Hyperwave server */
+void php3_hw_identify(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       int link, type;
+       char *name, *passwd, *userdata;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_string(arg3);
+       link = arg1->value.lval;
+       name=arg2->value.str.val;
+       passwd=arg3->value.str.val;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       {
+       char *str;
+
+       if (0 != (ptr->lasterror = send_identify(ptr->socket, name, passwd, &userdata))) {
+               php3_error(E_WARNING, "send_identify returned -1\n");
+               if(ptr->username) free(ptr->username);
+               ptr->username = NULL;
+               RETURN_FALSE;
+       }
+
+       return_value->value.str.val = userdata;
+       return_value->value.str.len = strlen(userdata);
+       return_value->type = IS_STRING;
+       if(ptr->username) free(ptr->username);
+       str = userdata;
+       while((*str != 0) && (*str != ' '))
+               str++;
+       if(*str != '\0')
+               ptr->username = strdup(++str);
+       else
+               ptr->username = NULL;
+       }
+}
+/* }}} */
+
+/* {{{ proto array hw_objrec2array(string objrec)
+   Returns object array of object record*/
+void php3_hw_objrec2array(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string(arg1);
+       make_return_array_from_objrec(&return_value, arg1->value.str.val);
+}
+/* }}} */
+
+/* {{{ proto string hw_array2objrec(array objarr)
+   Returns object record of object array */
+void php3_hw_array2objrec(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1;
+       char *objrec, *retobj;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_string(arg1);
+       objrec = make_objrec_from_array(arg1->value.ht);
+       if(objrec) {
+               retobj = estrdup(objrec);
+               free(objrec);
+               RETURN_STRING(retobj, 0);
+       } else
+               RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto array hw_incollections(int link, array objids, array collids, int para)
+   Returns object ids which are in collections */
+void php3_hw_incollections(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3, *arg4;
+       int type, link, i;
+       hw_connection *ptr;
+       int cobjids, ccollids, *objectIDs, *collIDs, cretids, *retIDs, retcoll;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 4 || getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_array(arg2);
+       convert_to_array(arg3);
+       convert_to_long(arg4);
+       link = arg1->value.lval;
+       retcoll=arg4->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       cobjids = _php3_hash_num_elements(arg2->value.ht);
+       if(NULL == (objectIDs = make_ints_from_array(arg2->value.ht))) {
+               php3_error(E_WARNING, "Could not create Int Array from Array\n");
+               RETURN_FALSE;
+       }
+
+       ccollids = _php3_hash_num_elements(arg3->value.ht);
+       if(NULL == (collIDs = make_ints_from_array(arg3->value.ht))) {
+               php3_error(E_WARNING, "Could not create Int Array from Array\n");
+               efree(objectIDs);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_incollections(ptr->socket, retcoll,
+                                                      cobjids, objectIDs,
+                                                      ccollids, collIDs,
+                                                      &cretids, &retIDs))) {
+               if(objectIDs) efree(objectIDs);
+               if(collIDs) efree(collIDs);
+               RETURN_FALSE;
+       }
+
+       if(objectIDs) efree(objectIDs);
+       if(collIDs) efree(collIDs);
+
+       if (array_init(return_value) == FAILURE) {
+               efree(retIDs);
+               RETURN_FALSE;
+       }
+
+       for(i=0; i<cretids; i++)
+               add_index_long(return_value, i, retIDs[i]);
+       efree(retIDs);
+
+}
+/* }}} */
+
+/* {{{ proto void hw_inscoll(int link, int parentid, array objarr)
+   Inserts collection */
+void php3_hw_inscoll(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3;
+       char *objrec;
+       int id, newid, type, link;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_array(arg3);
+       link = arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       if(NULL == (objrec = make_objrec_from_array(arg3->value.ht))) {
+               php3_error(E_WARNING, "Could not create Object Record from Array\n");
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_inscoll(ptr->socket, id, objrec, &newid))) {
+               if(objrec) free(objrec);
+               RETURN_FALSE;
+       }
+
+       if(objrec) free(objrec);
+       RETURN_LONG(newid);
+}
+/* }}} */
+
+/* {{{ proto void hw_inscoll(int link, int parentid, array objarr [, string text])
+   Inserts document */
+void php3_hw_insdoc(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *argv[4];
+       char *objrec, *text;
+       int id, newid, type, link, argc;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       argc = ARG_COUNT(ht);
+       if((argc < 3) || (argc > 4))
+               WRONG_PARAM_COUNT;
+
+       if (getParametersArray(ht, argc, argv) == FAILURE)
+               WRONG_PARAM_COUNT;
+
+       convert_to_long(argv[0]);
+       convert_to_long(argv[1]);
+       convert_to_string(argv[2]);
+       if(argc == 4) {
+               convert_to_string(argv[3]);
+               text = argv[3]->value.str.val;
+       } else {
+               text = NULL;
+       }
+       link = argv[0]->value.lval;
+       id = argv[1]->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+        objrec = argv[2]->value.str.val;
+       if (0 != (ptr->lasterror = send_insdoc(ptr->socket, id, objrec, text, &newid))) {
+               RETURN_FALSE;
+       }
+
+       RETURN_LONG(newid);
+}
+/* }}} */
+
+/* {{{ proto int hw_getsrcbydestobj(int link, int destid)
+   Returns object id of source docuent by destination anchor */
+void php3_hw_getsrcbydestobj(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2;
+       int link, type, id;
+       int count;
+       char  **childObjRecs = NULL;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &arg1, &arg2) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       link=arg1->value.lval;
+       id=arg2->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = send_getsrcbydest(ptr->socket, id, &childObjRecs, &count))) {
+               php3_error(E_WARNING, "send_command (getsrcbydest) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       /* create return value and free all memory */
+       if( 0 > make_return_objrec(&return_value, childObjRecs, count))
+               RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string hw_getrellink(int link, int rootid, int sourceid, int destid)
+   Get link form source to dest relative to rootid */
+void php3_hw_getrellink(INTERNAL_FUNCTION_PARAMETERS) {
+       pval *arg1, *arg2, *arg3, *arg4;
+       int link, type;
+       int rootid, destid, sourceid;
+       char *anchorstr;
+       hw_connection *ptr;
+       TLS_VARS;
+
+       if (ARG_COUNT(ht) != 4 || getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       convert_to_long(arg2);
+       convert_to_long(arg3);
+       convert_to_long(arg4);
+       link=arg1->value.lval;
+       rootid=arg2->value.lval;
+       sourceid=arg3->value.lval;
+       destid=arg4->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+
+       set_swap(ptr->swap_on);
+       if (0 != (ptr->lasterror = getrellink(ptr->socket, rootid, sourceid, destid, &anchorstr))) {
+               php3_error(E_WARNING, "command (getrellink) returned -1\n");
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING(anchorstr, 0);
+}
+/* }}} */
+       
+
+void php3_info_hw()
+{
+       php3_printf("HG-CSP Version: 7.17");
+}
+
+void php3_hw_connection_info(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *arg1;
+       hw_connection *ptr;
+       int link, type;
+
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+       convert_to_long(arg1);
+       link=arg1->value.lval;
+       ptr = php3_list_find(link,&type);
+       if(!ptr || (type!=php3_hw_module.le_socketp && type!=php3_hw_module.le_psocketp)) {
+               php3_error(E_WARNING,"Unable to find file identifier %d",link);
+               RETURN_FALSE;
+       }
+       
+       php3_printf("Hyperwave Info:\nhost=%s,\nserver string=%s\nversion=%d\nswap=%d\n", ptr->hostname, ptr->server_string, ptr->version, ptr->swap_on);
+}
+
+void print_msg(hg_msg *msg, char *str, int txt)
+{
+     char *ptr;
+     int  i;
+
+     fprintf(stdout, "\nprint_msg: >>%s<<\n", str);
+     fprintf(stdout, "print_msg: length  = %d\n", msg->length);
+     fprintf(stdout, "print_msg: msgid = %d\n", msg->version_msgid);
+     fprintf(stdout, "print_msg: msg_type  = %d\n", msg->msg_type);
+     if ( msg->length > HEADER_LENGTH )  {
+          ptr = msg->buf;
+          for ( i = 0; i < msg->length-HEADER_LENGTH; i++ )  {
+               if ( *ptr == '\n' )
+                    fprintf(stdout, "%c", *ptr++);
+               else if ( iscntrl(*ptr) )
+                    {fprintf(stdout, "."); ptr++;}
+               else
+                    fprintf(stdout, "%c", *ptr++);
+          }
+     }
+     fprintf(stdout, "\n\n");
+}
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
diff --git a/ext/hyperwave/hw.h b/ext/hyperwave/hw.h
new file mode 100644 (file)
index 0000000..21c2e6a
--- /dev/null
@@ -0,0 +1,122 @@
+/* 
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of the GNU General Public License as published by |
+   | the Free Software Foundation; either version 2 of the License, or    |
+   | (at your option) any later version.                                  |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            |
+   +----------------------------------------------------------------------+
+   | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
+   +----------------------------------------------------------------------+
+ */
+
+
+/* $Id$ */
+
+#ifndef _HW_H
+#define _HW_H
+
+#if HYPERWAVE
+#include "hg_comm.h"
+
+extern php3_module_entry hw_module_entry;
+#define hw_module_ptr &hw_module_entry
+
+typedef struct {
+  long default_link;
+  long num_links,num_persistent;
+  long max_links,max_persistent;
+  long allow_persistent;
+  int le_socketp, le_psocketp, le_document;
+} hw_module;
+
+extern hw_module php3_hw_module;
+
+typedef struct {
+        int size;
+        char *data;
+        char *attributes;
+        char *bodytag;
+} hw_document;
+
+extern hw_connection php3_hw_connection;
+
+extern int php3_minit_hw(INIT_FUNC_ARGS);
+extern void php3_hw_connect(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_pconnect(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_close(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_root(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_info(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_error(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_errormsg(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_mv(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_cp(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_deleteobject(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_changeobject(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getparents(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getparentsobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_children(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_childrenobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getchildcoll(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getchildcollobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getobject(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getandlock(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_unlock(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_gettext(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_edittext(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getcgi(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getremote(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getremotechildren(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_pipedocument(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_pipecgi(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_insertdocument(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_docbyanchorobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_docbyanchor(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getobjectbyquery(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getobjectbyqueryobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getobjectbyquerycoll(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getobjectbyquerycollobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getchilddoccoll(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getchilddoccollobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getanchors(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getanchorsobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getusername(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_setlinkroot(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_inscoll(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_incollections(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_insertobject(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_insdoc(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_identify(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_free_document(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_new_document(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_output_document(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_document_size(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_document_attributes(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_document_bodytag(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_document_content(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_objrec2array(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_array2objrec(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_connection_info(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_info_hw(void);
+extern void php3_hw_getsrcbydestobj(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_getrellink(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_dummy(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_who(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_hw_stat(INTERNAL_FUNCTION_PARAMETERS);
+#else
+#define hw_module_ptr NULL
+#endif /* HYPERWAVE */
+#endif /* _HW_H */
+
diff --git a/ext/hyperwave/hw_error.h b/ext/hyperwave/hw_error.h
new file mode 100644 (file)
index 0000000..9730995
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of the GNU General Public License as published by |
+   | the Free Software Foundation; either version 2 of the License, or    |
+   | (at your option) any later version.                                  |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of the GNU General Public License    |
+   | along with this program; if not, write to the Free Software          |
+   | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            |
+   +----------------------------------------------------------------------+
+   | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
+   +----------------------------------------------------------------------+
+ */
+
+
+/* $Id$ */
+#ifndef _HW_ERROR_H
+#define _HW_ERROR_H
+
+#if HYPERWAVE
+
+#define NOACCESS 1 /* Access denied */
+#define NODOCS 2 /* No documents */
+#define NONAME 3 /* No collection name */
+#define NODOC 4 /* Object is not a document */
+#define NOOBJ 5 /* No object received */
+#define NOCOLLS 6 /* No collections received */
+#define DBSTUBNG 7 /* Connection to low-level database failed */
+#define NOTFOUND 8 /* Object not found */
+#define EXIST 9 /* Collection already exists */
+#define FATHERDEL 10 /* parent collection disappeared */
+#define FATHNOCOLL 11 /* parent collection not a collection */
+#define NOTEMPTY 12 /* Collection not empty */
+#define DESTNOCOLL 13 /* Destination not a collection */
+#define SRCEQDEST 14 /* Source equals destination */
+#define REQPEND 15 /* Request pending */
+#define TIMEOUT 16 /* Timeout */
+#define NAMENOTUNIQUE 17 /* Name not unique */
+#define WRITESTOPPED 18 /* Database now read-only; try again later */
+#define LOCKED 19 /* Object locked; try again later */
+#define CHANGEBASEFLD 20 /* Change of base-attribute */
+#define NOTREMOVED 21 /* Attribute not removed */
+#define FLDEXISTS 22 /* Attribute exists */
+#define CMDSYNTAX 23 /* Syntax error in command */
+#define NOLANGUAGE 24 /* No or unknown language specified */
+#define WRGTYPE 25 /* Wrong type in object */
+#define WRGVERSION 26 /* Client version too old */
+#define CONNECTION 27 /* No connection to other server */
+#define SYNC 28 /* Synchronization error */
+#define NOPATH 29 /* No path entry */
+#define WRGPATH 30 /* Wrong path entry */
+#define PASSWD 31 /* Wrong password (server-to-server server authentication) */
+#define LC_NO_MORE_USERS 32 /* No more users for license */
+#define LC_NO_MORE_DOCS 33 /* No more documents for this session and license */
+#define RSERV_NRESP 34 /* Remote server not responding */
+#define Q_OVERFLOW 35 /* Query overflow */
+#define USR_BREAK 36 /* Break by user */
+#define N_IMPL 37 /* Not implemented */
+#define WRG_VALUE 38 /* Wrong value */
+#define INSUFF_FUNDS 39 /* Insufficient funds */
+#define REORG 40 /* Reorganization in progress */
+#define USER_LIMIT 41 /* Limit of simultaneous users reached */
+#define FTCONNECT 513 /* No connection to fulltext server */
+#define FTTIMEOUT 514 /* Connection timed out */
+#define FTINDEX 515 /* Something wrong with fulltext index */
+#define FTSYNTAX 516 /* Query syntax error */
+#define REQUESTPENDING 1025 /* Request pending */
+#define NOCONNECTION 1026 /* No connection to document server */
+#define WRONGVERSION 1027 /* Wrong protocol version */
+#define NOTINITIALIZED 1028 /* Not initialized */
+#define BADREQUEST 1029 /* Bad request */
+#define BADLRN 1030 /* Bad document number */
+#define OPENSTORE_WRITE 1031 /* Cannot write to local store */
+#define OPENSTORE_READ 1032 /* Cannot read from local store */
+#define READSTORE 1033 /* Store read error */
+#define WRITESTORE 1034 /* Write error */
+#define CLOSESTORE 1035 /* Close error */
+#define BADPATH 1036 /* Bad path */
+#define NOPATHDC 1037 /* No path */
+#define OPENFILE 1038 /* Cannot open file */
+#define READFILE 1039 /* Cannot read from file // same */
+#define WRITEFILE 1040 /* Cannot write to file */
+#define CONNECTCLIENT 1041 /* Could not connect to client */
+#define ACCEPT 1042 /* Could not accept connection */
+#define READSOCKET 1043 /* Could not read from socket */
+#define WRITESOCKET 1044 /* Could not write to socket */
+#define TOOMUCHDATA 1046 /* Received too much data */
+#define TOOFEWDATA 1047 /* Received too few data // ... */
+#define NOTIMPLEMENTED 1049 /* Not implemented */
+#define USERBREAK 1050 /* User break  */
+#define INTERNAL 1051 /* Internal error */
+#define INVALIDOBJECT 1052 /* Invalid object */
+#define JOBTIMEOUT 1053 /* Job timed out */
+#define OPENPORT 1054 /* Cannot open port // ... for several resons */
+#define NODATA 1055 /* Received no data  */
+#define NOPORT 1056 /* No port to handle this request */
+#define NOTCACHED 1057 /* Document not cached */
+#define BADCACHETYPE 1058 /* Bad cache type  */
+#define OPENCACHE_WRITE 1059 /* Cannot write to cache */
+#define OPENCACHE_READ 1060 /* Cannot read from cache // same */
+#define NOSOURCE 1061 /* Do not know what to read */
+#define CLOSECACHE 1062 /* Could not insert into cache  */
+#define CONNECTREMOTE 1063 /* Could not connect to remote server */
+#define LOCKREFUSED 1064 /* Lock refused // could not lock the stores */
+
+#endif
+#endif
diff --git a/ext/hyperwave/setup.stub b/ext/hyperwave/setup.stub
new file mode 100644 (file)
index 0000000..5109905
--- /dev/null
@@ -0,0 +1,6 @@
+# $Source$
+# $Id$
+
+define_option with-hyperwave 'Hyperwave support?' yesno no \
+'     Whether to build with Hyperwave support. More\n
+     information about Hyperwave can be found at http://www.hyperwave.com.'
diff --git a/ext/rpc/com/COM.c b/ext/rpc/com/COM.c
new file mode 100644 (file)
index 0000000..17e4a28
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 4.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997,1998 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of one of the following licenses:                 |
+   |                                                                      |
+   |  A) the GNU General Public License as published by the Free Software |
+   |     Foundation; either version 2 of the License, or (at your option) |
+   |     any later version.                                               |
+   |                                                                      |
+   |  B) the PHP License as published by the PHP Development Team and     |
+   |     included in the distribution in the file: LICENSE                |
+   |                                                                      |
+   | This program is distributed in the hope that it will be useful,      |
+   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
+   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
+   | GNU General Public License for more details.                         |
+   |                                                                      |
+   | You should have received a copy of both licenses referred to here.   |
+   | If you did not, or have any questions about PHP licensing, please    |
+   | contact core@php.net.                                                |
+   +----------------------------------------------------------------------+
+   | Author: Zeev Suraski <zeev@zend.com>                                 |
+   +----------------------------------------------------------------------+
+ */
+
+
+/*
+ * This module implements support for COM components that support the IDispatch
+ * interface.  Both local (COM) and remote (DCOM) components can be accessed.
+ *
+ * Type libraries can be loaded (in order for PHP to recognize automation constants)
+ * by specifying a typelib_file in the PHP .ini file.  That file should contain
+ * paths to type libraries, one in every line.  By default, constants are registered
+ * as case-sensitive.  If you want them to be defined as case-insensitive, add
+ * #case_insensitive or #cis at the end of the type library path.
+ *
+ * This is also the first module to demonstrate Zend's OO syntax overloading
+ * capabilities.  CORBA coders are invited to write a CORBA module as well!
+ *
+ * Zeev
+ */
+
+#if WIN32|WINNT
+
+#define _WIN32_DCOM
+
+#include "php.h"
+#include "php3_COM.h"
+#include "zend_compile.h"
+#include "php_ini.h"
+
+#include "objbase.h"
+#include "olestd.h" 
+#include <ctype.h> 
+
+static int le_idispatch;
+
+function_entry COM_functions[] = {
+       {"com_load",            php3_COM_load,          NULL},
+       {"com_invoke",          php3_COM_invoke,        NULL},
+
+       PHP_FE(com_propget,             NULL)
+       PHP_FE(com_propput,             NULL)
+
+       PHP_NAMED_FE(com_get,           php3_com_propget,       NULL)
+       PHP_NAMED_FE(com_propset,       php3_com_propput,       NULL)
+       PHP_NAMED_FE(com_set,           php3_com_propput,       NULL)
+
+       {NULL, NULL, NULL}
+};
+
+php3_module_entry COM_module_entry = {
+       "Win32 COM", COM_functions, php3_minit_COM, php3_mshutdown_COM, NULL, NULL, NULL, STANDARD_MODULE_PROPERTIES
+};
+
+void php_register_COM_class();
+
+static int php_COM_load_typelib(char *typelib_name, int mode);
+
+static char *_php3_COM_error_message(HRESULT hr)
+{
+       void *pMsgBuf;
+
+       if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+               hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgBuf, 0, NULL)) {
+               char error_string[] = "No description available";
+               
+               pMsgBuf = LocalAlloc(LMEM_FIXED, sizeof(error_string));
+               memcpy(pMsgBuf, error_string, sizeof(error_string));
+       }
+
+       return pMsgBuf;
+}
+
+
+static OLECHAR *php_char_to_OLECHAR(char *C_str, uint strlen)
+{
+       OLECHAR *unicode_str = (OLECHAR *) emalloc(sizeof(OLECHAR)*(strlen+1));
+       OLECHAR *unicode_ptr = unicode_str;
+
+       while (*C_str) {
+               *unicode_ptr++ = (unsigned short) *C_str++;
+       }
+       *unicode_ptr = 0;
+
+       return unicode_str;
+}
+
+
+char *php_OLECHAR_to_char(OLECHAR *unicode_str, uint *out_length, int persistent)
+{
+       uint length = OLESTRLEN(unicode_str);
+       char *C_str = (char *) pemalloc(length+1, persistent), *p = C_str;
+
+       while (*unicode_str) {
+               *p++ = (char) *unicode_str++;
+       }
+       *p = 0;
+
+       if (out_length) {
+               *out_length = length;
+       }
+
+       return C_str;
+}
+
+
+static char *_php3_string_from_clsid(CLSID *clsid)
+{
+       LPOLESTR ole_clsid;
+       char *clsid_str;
+
+       StringFromCLSID(clsid, &ole_clsid);
+       //s_clsid = OLE2A(ole_clsid);
+       clsid_str = php_OLECHAR_to_char(ole_clsid, NULL, 0);
+       LocalFree(ole_clsid);
+
+       return clsid_str;
+}
+
+
+static void _php3_idispatch_destructor(IDispatch *i_dispatch)
+{
+       i_dispatch->lpVtbl->Release(i_dispatch);
+}
+
+
+static PHP_INI_MH(OnTypelibFileChange)
+{
+       FILE *typelib_file;
+       char *typelib_name_buffer;
+#if SUPPORT_INTERACTIVE
+       int interactive;
+       ELS_FETCH();
+
+       interactive = EG(interactive);
+#endif
+
+
+       if (!new_value || (typelib_file=fopen(new_value, "r"))==NULL) {
+               return FAILURE;
+       }
+
+#if SUPPORT_INTERACTIVE
+       if (interactive) {
+               printf("Loading type libraries...");
+               fflush(stdout);
+       }
+#endif
+
+       typelib_name_buffer = (char *) malloc(sizeof(char)*1024);
+
+       while (fgets(typelib_name_buffer, 1024, typelib_file)) {
+               char *typelib_name;
+               char *modifier;
+               int mode = CONST_PERSISTENT|CONST_CS;
+
+               if (typelib_name_buffer[0]==';') {
+                       continue;
+               }
+               typelib_name = strtok(typelib_name_buffer, "\r\n"); /* get rid of newlines */
+               typelib_name = strtok(typelib_name, "#");
+               modifier = strtok(NULL, "#");
+               if (modifier) {
+                       if (!strcmp(modifier, "cis") || !strcmp(modifier, "case_insensitive")) {
+                               mode &= ~CONST_CS;
+                       }
+               }
+#if SUPPORT_INTERACTIVE
+               if (interactive) {
+                       printf("\rLoading %-60s\r", typelib_name);
+               }
+#endif
+               php_COM_load_typelib(typelib_name, mode);
+       }
+
+       free(typelib_name_buffer);
+       fclose(typelib_file);
+
+#if SUPPORT_INTERACTIVE
+       if (interactive) {
+               printf("\r%70s\r", "");
+       }
+#endif
+
+       return SUCCESS;
+}
+
+
+PHP_INI_BEGIN()
+       PHP_INI_ENTRY("allow_dcom",                     "0",            PHP_INI_SYSTEM,         NULL,                                   NULL)
+       PHP_INI_ENTRY("typelib_file",           NULL,           PHP_INI_SYSTEM,         OnTypelibFileChange,    NULL)
+PHP_INI_END()
+
+
+int php3_minit_COM(INIT_FUNC_ARGS)
+{
+       CoInitialize(NULL);
+       le_idispatch = register_list_destructors(_php3_idispatch_destructor,NULL);
+       php_register_COM_class();
+       REGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+
+int php3_mshutdown_COM(SHUTDOWN_FUNC_ARGS)
+{
+       CoUninitialize();
+       UNREGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+
+void php3_COM_load(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval *module_name, *server_name=NULL;
+       CLSID clsid;
+       HRESULT hr;
+       OLECHAR *ProgID;
+       IDispatch FAR *i_dispatch = NULL;
+       char *error_message;
+       char *clsid_str;
+
+       switch (ARG_COUNT(ht)) {
+               case 1:
+                       getParameters(ht, 1, &module_name);
+                       break;
+               case 2:
+                       if (!INI_INT("allow_dcom")) {
+                               php3_error(E_WARNING, "DCOM is disabled");
+                               RETURN_FALSE;
+                       }
+                       getParameters(ht, 2, &module_name, &server_name);
+                       convert_to_string(server_name);
+                       break;
+               default:
+                       WRONG_PARAM_COUNT;
+                       break;
+       }
+
+       convert_to_string(module_name);
+       ProgID = php_char_to_OLECHAR(module_name->value.str.val, module_name->value.str.len);
+       hr=CLSIDFromProgID(ProgID, &clsid);
+       efree(ProgID);
+
+       // obtain CLSID
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);    
+               php3_error(E_WARNING,"Invalid ProgID:  %s\n", error_message);
+               LocalFree(error_message);
+               RETURN_FALSE;
+       }
+
+       // obtain IDispatch
+       if (!server_name) {
+               hr=CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (void **) &i_dispatch);
+       } else {
+               COSERVERINFO server_info;
+               MULTI_QI pResults;
+
+               server_info.dwReserved1=0;
+               server_info.dwReserved2=0;
+               server_info.pwszName = php_char_to_OLECHAR(server_name->value.str.val, server_name->value.str.len);
+               server_info.pAuthInfo=NULL;
+
+               pResults.pIID = &IID_IDispatch;
+               pResults.pItf = NULL;
+               pResults.hr = S_OK;
+               hr=CoCreateInstanceEx(&clsid, NULL, CLSCTX_SERVER, &server_info, 1, &pResults);
+               if (SUCCEEDED(hr)) {
+                       hr = pResults.hr;
+                       i_dispatch = (IDispatch *) pResults.pItf;
+               }
+               efree(server_info.pwszName);
+       }
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               clsid_str = _php3_string_from_clsid(&clsid);
+               php3_error(E_WARNING,"Unable to obtain IDispatch interface for CLSID %s:  %s",clsid_str,error_message);
+               LocalFree(error_message);
+               efree(clsid_str);
+               RETURN_FALSE;
+       }
+
+       RETURN_LONG(php3_list_insert(i_dispatch,le_idispatch));
+}
+
+
+static void php_variant_to_pval(VARIANTARG *var_arg, pval *pval_arg, int persistent)
+{
+       switch (var_arg->vt) {
+               case VT_EMPTY:
+                       var_uninit(pval_arg);
+                       break;
+               case VT_UI1:
+                       pval_arg->value.lval = (long) var_arg->bVal;
+                       pval_arg->type = IS_LONG;
+                       break;
+               case VT_I2:
+                       pval_arg->value.lval = (long) var_arg->iVal;
+                       pval_arg->type = IS_LONG;
+                       break;
+               case VT_I4:
+                       pval_arg->value.lval = var_arg->lVal;
+                       pval_arg->type = IS_LONG;
+                       break;
+               case VT_R4:
+                       pval_arg->value.dval = (double) var_arg->fltVal;
+                       pval_arg->type = IS_DOUBLE;
+                       break;
+               case VT_R8:
+                       pval_arg->value.dval = var_arg->dblVal;
+                       pval_arg->type = IS_DOUBLE;
+                       break;
+               case VT_BOOL:
+
+                       if (var_arg->boolVal & 0xFFFF) {
+                               pval_arg->value.lval = 1;
+                       } else {
+
+                               pval_arg->value.lval = 0;
+                       }
+
+                       pval_arg->type = IS_BOOL;
+                       break;
+               case VT_BSTR:
+                       pval_arg->value.str.val = php_OLECHAR_to_char(var_arg->bstrVal, &pval_arg->value.str.len, persistent);
+                       pval_arg->type = IS_STRING;
+                       break;
+               case VT_UNKNOWN:
+               case VT_DISPATCH:
+                       /* possibly, return IDispatch as a new COM object.  right now - just get rid of it */
+                       var_arg->pdispVal->lpVtbl->Release(var_arg->pdispVal);
+                       var_reset(pval_arg);
+                       break;
+               default:
+                       php3_error(E_WARNING,"Unsupported variant type");
+                       var_reset(pval_arg);
+                       break;
+       }
+}
+
+
+static void _php3_pval_to_variant(pval *pval_arg, VARIANTARG *var_arg)
+{
+       OLECHAR *unicode_str;
+
+       switch (pval_arg->type) {
+       case IS_OBJECT:
+       case IS_ARRAY:
+               var_arg->vt = VT_EMPTY;
+               break;
+       case IS_LONG:
+       case IS_BOOL:
+               var_arg->vt = VT_I4;  // assuming 32-bit platform
+               var_arg->lVal = pval_arg->value.lval;
+               break;
+       case IS_DOUBLE:
+               var_arg->vt = VT_R8;  // assuming 64-bit double precision
+               var_arg->dblVal = pval_arg->value.dval;
+               break;
+       case IS_STRING:
+               unicode_str = php_char_to_OLECHAR(pval_arg->value.str.val, pval_arg->value.str.len);
+               var_arg->bstrVal = SysAllocString(unicode_str);
+               var_arg->vt = VT_BSTR;
+               efree(unicode_str);
+               break;
+       }
+}
+
+
+
+int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_result, pval **arguments, int arg_count)
+{
+       DISPID dispid;
+       HRESULT hr;
+       OLECHAR *funcname;
+       char *error_message;
+       VARIANTARG *variant_args;
+       int current_arg, current_variant;
+       DISPPARAMS dispparams;
+
+       funcname = php_char_to_OLECHAR(function_name->value.str.val, function_name->value.str.len);
+
+       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &funcname,
+                                                                                       1, LOCALE_SYSTEM_DEFAULT, &dispid);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"Unable to lookup %s:  %s\n", function_name->value.str.val, error_message);
+               LocalFree(error_message);
+               efree(funcname);
+               return FAILURE;
+       }
+
+       variant_args = (VARIANTARG *) emalloc(sizeof(VARIANTARG)*arg_count);
+
+       for (current_arg=0; current_arg<arg_count; current_arg++) {
+               current_variant = arg_count - current_arg - 1;
+               _php3_pval_to_variant(arguments[current_arg], &variant_args[current_variant]);
+       }
+
+
+       dispparams.rgvarg = variant_args;
+       dispparams.rgdispidNamedArgs = NULL;
+       dispparams.cArgs = arg_count;
+       dispparams.cNamedArgs = 0;
+
+       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
+                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
+                                                                       &dispparams, var_result, NULL, 0);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"Invoke() failed:  %s\n", error_message);
+               LocalFree(error_message);
+               efree(funcname);
+               efree(variant_args);
+               return FAILURE;
+       }
+
+       efree(variant_args);
+       efree(funcname);
+       return SUCCESS;
+}
+
+
+void php3_COM_invoke(INTERNAL_FUNCTION_PARAMETERS)
+{
+       pval **arguments;
+       pval *object, *function_name;
+       IDispatch *i_dispatch;
+       int type;
+       int arg_count = ARG_COUNT(ht);
+       VARIANTARG var_result;
+
+       if (arg_count<2) {
+               WRONG_PARAM_COUNT;
+       }
+       arguments = (pval **) emalloc(sizeof(pval *)*arg_count);
+       if (getParametersArray(ht, arg_count, arguments)==FAILURE) {
+               RETURN_FALSE;
+       }
+
+       object = arguments[0];
+       function_name = arguments[1];
+
+       /* obtain i_dispatch interface */
+       convert_to_long(object);
+       i_dispatch = php3_list_find(object->value.lval, &type);
+       if (!i_dispatch || (type!=le_idispatch)) {
+               php3_error(E_WARNING,"%d is not a COM object handler", function_name->value.str.val);
+               RETURN_FALSE;
+       }
+
+       /* obtain property/method handler */
+       convert_to_string(function_name);
+
+       if (do_COM_invoke(i_dispatch, function_name, &var_result, arguments+2, arg_count-2)==FAILURE) {
+               RETURN_FALSE;
+       }
+       efree(arguments);
+
+       php_variant_to_pval(&var_result, return_value, 0);
+}
+
+
+
+static int do_COM_offget(VARIANTARG *var_result, VARIANTARG *array, pval *arg_property, int cleanup)
+{
+       switch (array->vt) {
+               case VT_DISPATCH:       {       /* a Collection, possibly */
+                       pval function_name;
+                       IDispatch *i_dispatch = array->pdispVal;
+                       int retval;
+
+                       function_name.value.str.val = "Item";
+                       function_name.value.str.len = 4;
+                       function_name.type = IS_STRING;
+                       retval = do_COM_invoke(i_dispatch, &function_name, var_result, &arg_property, 1);
+                       if (cleanup) {
+                               i_dispatch->lpVtbl->Release(i_dispatch);
+                       }
+                       return retval;
+               }
+       }
+       return FAILURE;
+}
+
+
+static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *arg_property, int cleanup)
+{
+       DISPID dispid;
+       HRESULT hr;
+       OLECHAR *propname;
+       char *error_message;
+       DISPPARAMS dispparams;
+
+
+       /* obtain property handler */
+       propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len);
+
+       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname,
+                                                                                       1, LOCALE_SYSTEM_DEFAULT, &dispid);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"Unable to lookup %s:  %s\n", arg_property->value.str.val, error_message);
+               LocalFree(error_message);
+               efree(propname);
+               if (cleanup) {
+                       i_dispatch->lpVtbl->Release(i_dispatch);
+               }
+               return FAILURE;
+       }
+
+       dispparams.cArgs = 0;
+       dispparams.cNamedArgs = 0;
+
+       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
+                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
+                                                                       &dispparams, var_result, NULL, 0);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"PropGet() failed:  %s\n", error_message);
+               LocalFree(error_message);
+               efree(propname);
+               if (cleanup) {
+                       i_dispatch->lpVtbl->Release(i_dispatch);
+               }
+               return FAILURE;
+       }
+
+       efree(propname);
+       if (cleanup) {
+               i_dispatch->lpVtbl->Release(i_dispatch);
+       }
+       return SUCCESS;
+}
+
+
+
+static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_property, pval *value)
+{
+       DISPID dispid;
+       HRESULT hr;
+       OLECHAR *propname;
+       char *error_message;
+       VARIANTARG var_result;
+       DISPPARAMS dispparams;
+       VARIANTARG new_value;
+       DISPID mydispid = DISPID_PROPERTYPUT;
+
+
+       /* obtain property handler */
+       propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len);
+
+       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname,
+                                                                                       1, LOCALE_SYSTEM_DEFAULT, &dispid);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"Unable to lookup %s:  %s\n", arg_property->value.str.val, error_message);
+               LocalFree(error_message);
+               efree(propname);
+               RETURN_FALSE;
+       }
+
+
+       _php3_pval_to_variant(value, &new_value);
+       dispparams.rgvarg = &new_value;
+       dispparams.rgdispidNamedArgs = &mydispid;
+       dispparams.cArgs = 1;
+       dispparams.cNamedArgs = 1;
+
+       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
+                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
+                                                                       &dispparams, NULL, NULL, 0);
+
+       dispparams.cArgs = 0;
+       dispparams.cNamedArgs = 0;
+
+       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
+                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
+                                                                       &dispparams, &var_result, NULL, 0);
+
+       if (FAILED(hr)) {
+               error_message = _php3_COM_error_message(hr);
+               php3_error(E_WARNING,"PropPut() failed:  %s\n", error_message);
+               LocalFree(error_message);
+               efree(propname);
+               RETURN_FALSE;
+       }
+
+       php_variant_to_pval(&var_result, return_value, 0);
+
+       efree(propname);
+}
+
+
+PHP_FUNCTION(com_propget)
+{
+       pval *arg_idispatch, *arg_property;
+       int type;
+       IDispatch *i_dispatch;
+       VARIANTARG var_result;
+
+       if (ARG_COUNT(ht)!=2 || getParameters(ht, 2, &arg_idispatch, &arg_property)==FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       /* obtain i_dispatch interface */
+       convert_to_long(arg_idispatch);
+       /* obtain i_dispatch interface */
+       i_dispatch = php3_list_find(arg_idispatch->value.lval,&type);
+       if (!i_dispatch || (type!=le_idispatch)) {
+               php3_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
+       }       
+       convert_to_string(arg_property);
+
+       if (do_COM_propget(&var_result, i_dispatch, arg_property, 0)==FAILURE) {
+               RETURN_FALSE;
+       }
+       php_variant_to_pval(&var_result, return_value, 0);
+}
+
+
+PHP_FUNCTION(com_propput)
+{
+       pval *arg_idispatch, *arg_property, *arg_value;
+       int type;
+       IDispatch *i_dispatch;
+
+       if (ARG_COUNT(ht)!=3 || getParameters(ht, 3, &arg_idispatch, &arg_property, &arg_value)==FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       /* obtain i_dispatch interface */
+       convert_to_long(arg_idispatch);
+       /* obtain i_dispatch interface */
+       i_dispatch = php3_list_find(arg_idispatch->value.lval,&type);
+       if (!i_dispatch || (type!=le_idispatch)) {
+               php3_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
+       }       
+       convert_to_string(arg_property);
+
+       do_COM_propput(return_value, i_dispatch, arg_property, arg_value);
+}
+
+
+VARIANTARG _php_COM_get_property_handler(zend_property_reference *property_reference)
+{
+       zend_overloaded_element *overloaded_property;
+       zend_llist_element *element;
+       pval **idispatch_handle;
+       pval *object = *property_reference->object;
+       IDispatch *i_dispatch;
+       int type;
+       VARIANTARG var_result;
+
+       /*printf("Reading a property from a TestClass object:\n");*/
+
+
+       /* fetch the IDispatch interface */
+       zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
+       i_dispatch = php3_list_find((*idispatch_handle)->value.lval,&type);
+       if (!i_dispatch || (type!=le_idispatch)) {
+               /* bail out */
+       }
+
+       var_result.vt = VT_DISPATCH;
+       var_result.pdispVal = i_dispatch;
+
+       for (element=property_reference->elements_list.head; element; element=element->next) {
+               overloaded_property = (zend_overloaded_element *) element->data;
+               switch (overloaded_property->type) {
+                       case IS_ARRAY:
+                               if (do_COM_offget(&var_result, &var_result, &overloaded_property->element, element!=property_reference->elements_list.head)==FAILURE) {
+                                       /* bail out */
+                               }
+                               /*printf("Array offset:  ");*/
+                               break;
+                       case IS_OBJECT:
+                               if (var_result.vt != VT_DISPATCH) {
+                                       /* bail out */
+                               } else {
+                                       if (do_COM_propget(&var_result, var_result.pdispVal, &overloaded_property->element, element!=property_reference->elements_list.head)==FAILURE) {
+                                               /* bail out */
+                                       }
+                                       /*printf("Object property:  ");*/
+                               }
+                               break;
+                       case IS_METHOD:
+                               return var_result;
+                               break;
+               }
+               /*
+               switch (overloaded_property->element.type) {
+                       case IS_LONG:
+                               printf("%d (numeric)\n", overloaded_property->element.value.lval);
+                               break;
+                       case IS_STRING:
+                               printf("'%s'\n", overloaded_property->element.value.str.val);
+                               break;
+               }
+               */
+               pval_destructor(&overloaded_property->element);
+       }
+       return var_result;
+}
+
+
+pval php_COM_get_property_handler(zend_property_reference *property_reference)
+{
+       pval result;
+       VARIANTARG var_result = _php_COM_get_property_handler(property_reference);
+
+       php_variant_to_pval(&var_result, &result, 0);
+       return result;
+}
+
+
+int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value)
+{
+       pval result;
+       zend_overloaded_element *overloaded_property;
+       zend_llist_element *element;
+       pval **idispatch_handle;
+       pval *object = *property_reference->object;
+       IDispatch *i_dispatch;
+       int type;
+       VARIANTARG var_result;
+
+       /*printf("Reading a property from a TestClass object:\n");*/
+
+
+       /* fetch the IDispatch interface */
+       zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
+       i_dispatch = php3_list_find((*idispatch_handle)->value.lval,&type);
+       if (!i_dispatch || (type!=le_idispatch)) {
+               /* bail out */
+       }
+       var_result.vt = VT_DISPATCH;
+       var_result.pdispVal = i_dispatch;
+
+       for (element=property_reference->elements_list.head; element && element!=property_reference->elements_list.tail; element=element->next) {
+               overloaded_property = (zend_overloaded_element *) element->data;
+               switch (overloaded_property->type) {
+                       case IS_ARRAY:
+                               /*printf("Array offset:  ");*/
+                               break;
+                       case IS_OBJECT:
+                               if (var_result.vt != VT_DISPATCH) {
+                                       /* bail out */
+                               } else {
+                                       do_COM_propget(&var_result, i_dispatch, &overloaded_property->element, element!=property_reference->elements_list.head);
+                                       /*printf("Object property:  ");*/
+                               }
+                               break;
+                       case IS_METHOD:
+                               /* this shouldn't happen */
+                               return FAILURE;
+               }
+               /*
+               switch (overloaded_property->element.type) {
+                       case IS_LONG:
+                               printf("%d (numeric)\n", overloaded_property->element.value.lval);
+                               break;
+                       case IS_STRING:
+                               printf("'%s'\n", overloaded_property->element.value.str.val);
+                               break;
+               }
+               */
+               pval_destructor(&overloaded_property->element);
+       }
+
+       if (var_result.vt != VT_DISPATCH) {
+               return FAILURE;
+       }
+       overloaded_property = (zend_overloaded_element *) element->data;
+       do_COM_propput(&result, var_result.pdispVal, &overloaded_property->element, value);
+       pval_destructor(&overloaded_property->element);
+       return SUCCESS;
+}
+
+
+
+void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
+{
+       zend_overloaded_element *overloaded_property;
+       pval *object = *property_reference->object;
+       zend_overloaded_element *function_name = (zend_overloaded_element *) property_reference->elements_list.tail->data;
+
+       if (zend_llist_count(&property_reference->elements_list)==1
+               && !strcmp(function_name->element.value.str.val, "com")) { /* constructor */
+               pval *object_handle;
+
+               php3_COM_load(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+               if (!zend_is_true(return_value)) {
+                       var_reset(object);
+                       return;
+               }
+               object_handle  = (pval *) emalloc(sizeof(pval));
+               *object_handle = *return_value;
+               pval_copy_constructor(object_handle);
+               object_handle->refcount = 1;
+               object_handle->is_ref=0;
+               zend_hash_index_update(object->value.obj.properties, 0, &object_handle, sizeof(pval *), NULL);
+               pval_destructor(&function_name->element);
+       } else {
+               VARIANTARG object_handle = _php_COM_get_property_handler(property_reference);
+               pval **arguments;
+               int arg_count = ARG_COUNT(ht);
+               VARIANTARG var_result;
+
+               if (object_handle.vt != VT_DISPATCH) {
+                       /* that shouldn't happen */
+                       return;
+               }
+               arguments = (pval **) emalloc(sizeof(pval *)*arg_count);
+               getParametersArray(ht, arg_count, arguments);
+
+               if (do_COM_invoke((IDispatch *) object_handle.pdispVal, &function_name->element, &var_result, arguments, arg_count)==FAILURE) {
+                       RETVAL_FALSE;
+               }
+               pval_destructor(&function_name->element);
+               efree(arguments);
+               php_variant_to_pval(&var_result, return_value, 0);
+       }
+
+       for (overloaded_property = (zend_overloaded_element *) zend_llist_get_first(&property_reference->elements_list);
+            overloaded_property;
+            overloaded_property = (zend_overloaded_element *) zend_llist_get_next(&property_reference->elements_list)) {
+               switch (overloaded_property->type) {
+               case IS_ARRAY:
+                       break;
+               case IS_OBJECT:
+                       break;
+               case IS_METHOD:
+
+                       break;
+               }
+       }
+}
+
+
+void php_register_COM_class()
+{
+       zend_class_entry class_entry, *registered_class;
+
+       class_entry.name = strdup("COM");
+       class_entry.name_length = sizeof("COM")-1;
+
+       class_entry.handle_property_get = php_COM_get_property_handler;
+       class_entry.handle_property_set = php_COM_set_property_handler;
+       class_entry.handle_function_call = php_COM_call_function_handler;
+       registered_class = register_internal_class(&class_entry);
+}
+
+
+static int php_COM_load_typelib(char *typelib_name, int mode)
+{
+       ITypeLib *TypeLib;
+       ITypeComp *TypeComp;
+       OLECHAR *p;
+       int i;
+       int interfaces;
+       ELS_FETCH();
+
+       p = php_char_to_OLECHAR(typelib_name, strlen(typelib_name));
+
+       if (FAILED(LoadTypeLib(p, &TypeLib))) {
+               efree(p);
+               return FAILURE;
+       }
+
+       interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
+
+       TypeLib->lpVtbl->GetTypeComp(TypeLib, &TypeComp);
+       for (i=0; i<interfaces; i++) {
+               TYPEKIND pTKind;
+
+               TypeLib->lpVtbl->GetTypeInfoType(TypeLib, i, &pTKind);
+               if (pTKind==TKIND_ENUM) {
+                       ITypeInfo *TypeInfo;
+                       VARDESC *pVarDesc;
+                       UINT NameCount;
+                       int j;
+#if 0
+                       BSTR bstr_EnumId;
+                       char *EnumId;
+
+                       TypeLib->lpVtbl->GetDocumentation(TypeLib, i, &bstr_EnumId, NULL, NULL, NULL);
+                       EnumId = php_OLECHAR_to_char(bstr_EnumId, NULL, 0);
+                       printf("Enumeration %d - %s:\n", i, EnumId);
+                       efree(EnumId);
+#endif
+
+                       TypeLib->lpVtbl->GetTypeInfo(TypeLib, i, &TypeInfo);
+
+                       j=0;
+                       while (TypeInfo->lpVtbl->GetVarDesc(TypeInfo, j, &pVarDesc)==S_OK) {
+                               BSTR bstr_ids;
+                               char *ids;
+                               zend_constant c;
+
+                               TypeInfo->lpVtbl->GetNames(TypeInfo, pVarDesc->memid, &bstr_ids, 1, &NameCount);
+                               if (NameCount!=1) {
+                                       j++;
+                                       continue;
+                               }
+                               LocalFree(bstr_ids);
+                               ids = php_OLECHAR_to_char(bstr_ids, NULL, 1);
+                               c.name_len = strlen(ids)+1;
+                               c.name = ids;
+                               php_variant_to_pval(pVarDesc->lpvarValue, &c.value, 1);
+                               c.flags = mode;
+
+                               zend_register_constant(&c ELS_CC);
+                               //printf("%s -> %ld\n", ids, pVarDesc->lpvarValue->lVal);
+                               j++;
+                       }
+                       TypeInfo->lpVtbl->Release(TypeInfo);
+               }
+       }
+
+
+       TypeLib->lpVtbl->Release(TypeLib);
+       efree(p);
+       return SUCCESS;
+}
+
+#endif
diff --git a/ext/rpc/com/php3_COM.h b/ext/rpc/com/php3_COM.h
new file mode 100644 (file)
index 0000000..ed9cc4f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _PHP3_COM_H
+#define _PHP3_COM_H
+
+#if WIN32|WINNT
+
+extern int php3_minit_COM(INIT_FUNC_ARGS);
+extern int php3_mshutdown_COM(SHUTDOWN_FUNC_ARGS);
+extern void php3_COM_load(INTERNAL_FUNCTION_PARAMETERS);
+extern void php3_COM_invoke(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_FUNCTION(com_propget);
+PHP_FUNCTION(com_propput);
+extern php3_module_entry COM_module_entry;
+#define COM_module_ptr &COM_module_entry
+
+#else
+
+#define COM_module_ptr NULL
+
+#endif  /* Win32|WINNT */
+
+#endif  /* _PHP3_COM_H */
diff --git a/setup b/setup
index e17ed3ac56cee032771ccb31a6726754d75d3cb5..e4c0ffb88414a6a6484239a871614e118b108a94 100644 (file)
--- a/setup
+++ b/setup
@@ -266,10 +266,6 @@ define_option with-interbase 'InterBase support?' yesnodir \
 '     Whether to build PHP with InterBase support. More\n
       information about InterBase can be found at http://www.interbase.com/.'
 
-define_option with-hyperwave 'Hyperwave support?' yesno no \
-'     Whether to build with Hyperwave support. More\n
-     information about Hyperwave can be found at http://www.hyperwave.com.'
-
 define_option with-ldap 'LDAP support?' yesnodir \
     'no /usr/local/ldap LDAP base install' \
 '     Whether to build with LDAP (Lightweight Directory Access Protocol)\n