Using yaz/log.h again. Added config file HTTP access.
[yazproxy-moved-to-github.git] / src / yaz-proxy.cpp
index b246554..935e453 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: yaz-proxy.cpp,v 1.4 2004-04-22 07:46:21 adam Exp $
+/* $Id: yaz-proxy.cpp,v 1.14 2004-12-13 20:52:33 adam Exp $
    Copyright (c) 1998-2004, Index Data.
 
 This file is part of the yaz-proxy.
@@ -38,15 +38,9 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <yaz/yaz-iconv.h>
 #include <yaz/log.h>
 #include <yaz/diagbib1.h>
-#include <yazproxy/proxy.h>
+#include "proxyp.h"
 #include <yaz/pquery.h>
-
-#if HAVE_XSLT
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/transform.h>
-#endif
+#include <yaz/otherinfo.h>
 
 static const char *apdu_name(Z_APDU *apdu)
 {
@@ -141,6 +135,9 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_s2z_stylesheet = 0;
     m_s2z_database = 0;
     m_schema = 0;
+    m_backend_type = 0;
+    m_backend_charset = 0;
+    m_frontend_type = 0;
     m_initRequest_apdu = 0;
     m_initRequest_mem = 0;
     m_initRequest_preferredMessageSize = 0;
@@ -166,22 +163,25 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
 #else
     m_time_tv = 0;
 #endif
+    m_usemarcon_ini_stage1 = 0;
+    m_usemarcon_ini_stage2 = 0;
+    m_usemarcon = new Yaz_usemarcon();
     if (!m_parent)
        low_socket_open();
 }
 
 Yaz_Proxy::~Yaz_Proxy()
 {
-    yaz_log(LOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
+    yaz_log(YLOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
            m_bytes_sent, m_bytes_recv);
     nmem_destroy(m_initRequest_mem);
     nmem_destroy(m_mem_invalid_session);
     nmem_destroy(m_referenceId_mem);
 
-    xfree (m_proxyTarget);
-    xfree (m_default_target);
-    xfree (m_proxy_authentication);
-    xfree (m_optimize);
+    xfree(m_proxyTarget);
+    xfree(m_default_target);
+    xfree(m_proxy_authentication);
+    xfree(m_optimize);
 
 #if HAVE_XSLT
     if (m_stylesheet_xsp)
@@ -190,6 +190,11 @@ Yaz_Proxy::~Yaz_Proxy()
     xfree (m_time_tv);
 
     xfree (m_schema);
+    xfree (m_backend_type);
+    xfree (m_backend_charset);
+    xfree (m_usemarcon_ini_stage1);
+    xfree (m_usemarcon_ini_stage2);
+    delete m_usemarcon;
     if (m_s2z_odr_init)
        odr_destroy(m_s2z_odr_init);
     if (m_s2z_odr_search)
@@ -235,14 +240,14 @@ Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
     Yaz_ProxyConfig *cfg = m_config;
     if (m_reconfig_flag)
     {
-       yaz_log(LOG_LOG, "reconfigure");
+       yaz_log(YLOG_LOG, "reconfigure");
        yaz_log_reopen();
        if (m_config_fname && cfg)
        {
-           yaz_log(LOG_LOG, "reconfigure config %s", m_config_fname);
+           yaz_log(YLOG_LOG, "reconfigure config %s", m_config_fname);
            int r = cfg->read_xml(m_config_fname);
            if (r)
-               yaz_log(LOG_WARN, "reconfigure failed");
+               yaz_log(YLOG_WARN, "reconfigure failed");
            else
            {
                m_log_mask = 0;
@@ -250,7 +255,7 @@ Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
            }
        }
        else
-           yaz_log(LOG_LOG, "reconfigure");
+           yaz_log(YLOG_LOG, "reconfigure");
        m_reconfig_flag = 0;
     }
     return cfg;
@@ -276,7 +281,7 @@ IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
     new_proxy->set_proxy_authentication(m_proxy_authentication);
     sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
     m_session_no++;
-    yaz_log (LOG_LOG, "%sNew session %s", new_proxy->m_session_str,
+    yaz_log (YLOG_LOG, "%sNew session %s", new_proxy->m_session_str,
             the_PDU_Observable->getpeername());
     return new_proxy;
 }
@@ -342,7 +347,7 @@ const char *Yaz_Proxy::load_balance(const char **url)
     const char *ret_spare = 0;
     for (i = 0; url[i]; i++)
     {
-       yaz_log(LOG_DEBUG, "%szurl=%s use=%d spare=%d",
+       yaz_log(YLOG_DEBUG, "%szurl=%s use=%d spare=%d",
                m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
        if (min_use > zurl_in_use[i])
        {
@@ -385,10 +390,11 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
 #endif
            xfree(m_default_target);
            m_default_target = xstrdup(proxy_host);
-           proxy_host = m_default_target;
        }
+       proxy_host = m_default_target;
        int client_idletime = -1;
        const char *cql2rpn_fname = 0;
+       const char *authentication = 0;
        url[0] = m_default_target;
        url[1] = 0;
        if (cfg)
@@ -401,7 +407,8 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                                 &m_keepalive_limit_bw,
                                 &m_keepalive_limit_pdu,
                                 &pre_init,
-                                &cql2rpn_fname);
+                                &cql2rpn_fname,
+                                &authentication);
        }
        if (client_idletime != -1)
        {
@@ -410,9 +417,11 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        }
        if (cql2rpn_fname)
            m_cql2rpn.set_pqf_file(cql2rpn_fname);
+       if (authentication)
+           set_proxy_authentication(authentication);
        if (!url[0])
        {
-           yaz_log(LOG_LOG, "%sNo default target", m_session_str);
+           yaz_log(YLOG_LOG, "%sNo default target", m_session_str);
            return 0;
        }
        // we don't handle multiplexing for cookie session, so we just
@@ -438,7 +447,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                // we have an initRequest we can safely do re-open
                if (c->m_waiting && apdu->which == Z_APDU_initRequest)
                {
-                   yaz_log (LOG_LOG, "%s REOPEN target=%s", m_session_str,
+                   yaz_log (YLOG_LOG, "%s REOPEN target=%s", m_session_str,
                             c->get_hostname());
                    c->close();
                    c->m_init_flag = 0;
@@ -462,24 +471,26 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                    c->m_server->m_client = 0;
                c->m_server = this;
                (parent->m_seqno)++;
-               yaz_log (LOG_DEBUG, "get_client 1 %p %p", this, c);
+               yaz_log (YLOG_DEBUG, "get_client 1 %p %p", this, c);
                return c;
            }
        }
     }
-    else if (!c)
+    else if (!c && apdu->which == Z_APDU_initRequest
+            && apdu->u.initRequest->idAuthentication == 0)
     {
-       // don't have a client session yet. Search in session w/o cookie
+       // anonymous sessions without cookie.
+       // if authentication is set it is NOT anonymous se we can't share them.
        for (c = parent->m_clientPool; c; c = c->m_next)
        {
-           assert (c->m_prev);
-           assert (*c->m_prev == c);
+           assert(c->m_prev);
+           assert(*c->m_prev == c);
            if (c->m_server == 0 && c->m_cookie == 0 && 
-               c->m_waiting == 0 &&
+               c->m_waiting == 0 && 
                !strcmp(m_proxyTarget, c->get_hostname()))
            {
                // found it in cache
-               yaz_log (LOG_LOG, "%sREUSE %d %s",
+               yaz_log (YLOG_LOG, "%sREUSE %d %s",
                         m_session_str, parent->m_seqno, c->get_hostname());
                
                c->m_seqno = parent->m_seqno;
@@ -503,7 +514,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
     {
        if (apdu->which != Z_APDU_initRequest)
        {
-           yaz_log (LOG_LOG, "%sno init request as first PDU", m_session_str);
+           yaz_log (YLOG_LOG, "%sno init request as first PDU", m_session_str);
            return 0;
        }
         Z_InitRequest *initRequest = apdu->u.initRequest;
@@ -522,15 +533,21 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                     odr_strdup (odr_encode(), m_proxy_authentication);
             }
         }
+       else
+       {
+           // the client use authentication. We set the keepalive PDU
+           // to 0 so we don't cache it in releaseClient
+           m_keepalive_limit_pdu = 0;
+       }
        // go through list of clients - and find the lowest/oldest one.
        Yaz_ProxyClient *c_min = 0;
        int min_seq = -1;
        int no_of_clients = 0;
        if (parent->m_clientPool)
-           yaz_log (LOG_DEBUG, "Existing sessions");
+           yaz_log (YLOG_DEBUG, "Existing sessions");
        for (c = parent->m_clientPool; c; c = c->m_next)
        {
-           yaz_log (LOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
+           yaz_log (YLOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
                               c->m_waiting, c->get_hostname(),
                               c->m_cookie ? c->m_cookie : "");
            no_of_clients++;
@@ -545,7 +562,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
            c = c_min;
            if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
            {
-               yaz_log (LOG_LOG, "%sMAXCLIENTS %d Destroy %d",
+               yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Destroy %d",
                         m_session_str, parent->m_max_clients, c->m_seqno);
                if (c->m_server && c->m_server != this)
                    delete c->m_server;
@@ -553,7 +570,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
            }
            else
            {
-               yaz_log (LOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
+               yaz_log (YLOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
                         m_session_str, parent->m_max_clients,
                         c->m_seqno, parent->m_seqno, c->get_hostname());
                xfree (c->m_cookie);
@@ -580,7 +597,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        }
        else
        {
-           yaz_log (LOG_LOG, "%sNEW %d %s",
+           yaz_log (YLOG_LOG, "%sNEW %d %s",
                     m_session_str, parent->m_seqno, m_proxyTarget);
            c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
            c->m_next = parent->m_clientPool;
@@ -617,7 +634,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        else
            c->set_APDU_yazlog(0);
     }
-    yaz_log (LOG_DEBUG, "get_client 3 %p %p", this, c);
+    yaz_log (YLOG_DEBUG, "get_client 3 %p %p", this, c);
     return c;
 }
 
@@ -631,24 +648,24 @@ void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
         Z_DiagRec *p = pp[i];
         if (p->which != Z_DiagRec_defaultFormat)
         {
-           yaz_log(LOG_LOG, "%sError no diagnostics", m_session_str);
+           yaz_log(YLOG_LOG, "%sError no diagnostics", m_session_str);
             return;
         }
         else
             r = p->u.defaultFormat;
         if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
             ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
-           yaz_log(LOG_LOG, "%sError unknown diagnostic set", m_session_str);
+           yaz_log(YLOG_LOG, "%sError unknown diagnostic set", m_session_str);
         switch (r->which)
         {
         case Z_DefaultDiagFormat_v2Addinfo:
-           yaz_log(LOG_LOG, "%sError %d %s:%s",
+           yaz_log(YLOG_LOG, "%sError %d %s:%s",
                    m_session_str,
                    *r->condition, diagbib1_str(*r->condition),
                    r->u.v2Addinfo);
             break;
         case Z_DefaultDiagFormat_v3Addinfo:
-           yaz_log(LOG_LOG, "%sError %d %s:%s",
+           yaz_log(YLOG_LOG, "%sError %d %s:%s",
                    m_session_str,
                    *r->condition, diagbib1_str(*r->condition),
                    r->u.v3Addinfo);
@@ -686,7 +703,7 @@ void Yaz_Proxy::convert_xsl_delay()
                r->u.octet_aligned->len);
 
            
-           yaz_log(LOG_LOG, "%sXSLT convert %d",
+           yaz_log(YLOG_LOG, "%sXSLT convert %d",
                    m_session_str, m_stylesheet_offset);
            res = xsltApplyStylesheet((xsltStylesheetPtr) m_stylesheet_xsp,
                                      doc, 0);
@@ -725,11 +742,86 @@ void Yaz_Proxy::convert_xsl_delay()
        timeout(0);
 }
 
-void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p)
+void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
+{
+    if (m_frontend_type != VAL_NONE)
+    {
+       int i;
+       for (i = 0; i < p->num_records; i++)
+       {
+           Z_NamePlusRecord *npr = p->records[i];
+           if (npr->which == Z_NamePlusRecord_databaseRecord)
+           {
+               Z_External *r = npr->u.databaseRecord;
+               if (r->which == Z_External_octet)
+               {
+#if HAVE_USEMARCON
+                   if (m_usemarcon_ini_stage1 && *m_usemarcon_ini_stage1)
+                   {
+                       if (!m_usemarcon->m_stage1)
+                       {
+                           m_usemarcon->m_stage1 = new CDetails();
+                       }
+                       m_usemarcon->m_stage1->SetIniFileName(m_usemarcon_ini_stage1);
+                       m_usemarcon->m_stage1->SetMarcRecord((char*) r->u.octet_aligned->buf, r->u.octet_aligned->len);
+                       int res = m_usemarcon->m_stage1->Start();
+                       if (res == 0)
+                       {
+                           char *converted;
+                           int convlen;
+                           m_usemarcon->m_stage1->GetMarcRecord(converted, convlen);
+                           if (m_usemarcon_ini_stage2 && *m_usemarcon_ini_stage2)
+                           {
+                               if (!m_usemarcon->m_stage2)
+                               {
+                                   m_usemarcon->m_stage2 = new CDetails();
+                               }
+                               m_usemarcon->m_stage2->SetIniFileName(m_usemarcon_ini_stage2);
+                               m_usemarcon->m_stage2->SetMarcRecord(converted, convlen);
+                               res = m_usemarcon->m_stage2->Start();
+                               if (res == 0)
+                               {
+                                   free(converted);
+                                   m_usemarcon->m_stage2->GetMarcRecord(converted, convlen);
+                               }
+                               else
+                               {
+                                   yaz_log(YLOG_LOG, "%sUSEMARCON stage 2 error %d", m_session_str, res);
+                               }
+                           }
+                           npr->u.databaseRecord =
+                               z_ext_record(odr_encode(),
+                                            m_frontend_type,
+                                            converted,
+                                            strlen(converted));
+                           free(converted);
+                       }
+                       else
+                       {
+                           yaz_log(YLOG_LOG, "%sUSEMARCON stage 1 error %d", m_session_str, res);
+                       }
+                       continue;
+                   }
+#endif
+                   npr->u.databaseRecord =
+                       z_ext_record(odr_encode(),
+                                    m_frontend_type,
+                                    (char*) r->u.octet_aligned->buf,
+                                    r->u.octet_aligned->len);
+               }
+           }
+       }
+    }
+}
+
+void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
+                                  const char *backend_charset)
 {
     int i;
 
-    yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC-8");
+    if (!backend_charset)
+       backend_charset = "MARC-8";
+    yaz_iconv_t cd = yaz_iconv_open("UTF-8", backend_charset);
     yaz_marc_t mt = yaz_marc_create();
     yaz_marc_xml(mt, YAZ_MARC_MARCXML);
     yaz_marc_iconv(mt, cd);
@@ -770,7 +862,7 @@ void Yaz_Proxy::logtime()
        long diff = (tv1.tv_sec - tv->tv_sec)*1000000 +
            (tv1.tv_usec - tv->tv_usec);
        if (diff >= 0)
-           yaz_log(LOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
+           yaz_log(YLOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
                    diff/1000000, (diff/1000)%1000);
     }
     tv->tv_sec = 0;
@@ -792,7 +884,7 @@ int Yaz_Proxy::send_http_response(int code)
     
     if (m_log_mask & PROXY_LOG_REQ_CLIENT)
     {
-       yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+       yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
                 gdu_name(gdu));
     }
     int len;
@@ -838,7 +930,7 @@ int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
                         soap_handlers, 0, m_s2z_stylesheet);
     if (m_log_mask & PROXY_LOG_REQ_CLIENT)
     {
-       yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+       yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
                 gdu_name(gdu));
     }
     int len;
@@ -943,8 +1035,8 @@ int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
     if (cfg)
     {
        int len;
-       char *b = cfg->get_explain(odr_encode(), 0 /* target */,
-                                  m_s2z_database, &len);
+       char *b = cfg->get_explain_doc(odr_encode(), 0 /* target */,
+                                      m_s2z_database, &len);
        if (b)
        {
            Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
@@ -1026,7 +1118,7 @@ int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
     {
        int len = 0;
        if (m_log_mask & PROXY_LOG_REQ_CLIENT)
-           yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+           yaz_log (YLOG_LOG, "%sSending %s to client", m_session_str,
                     apdu_name(apdu));
        int r = send_Z_PDU(apdu, &len);
        m_bytes_sent += len;
@@ -1062,15 +1154,22 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
        {
            if (p && p->which == Z_Records_DBOSD)
            {
+               if (m_backend_type
+#if HAVE_USEMARCON
+                   || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+                   )
+                   convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
                if (m_marcxml_flag)
-                   convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+                   convert_to_marcxml(p->u.databaseOrSurDiagnostics,
+                                      m_backend_charset);
                if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
                    return 0;
                    
            }
            if (sr->resultCount)
            {
-               yaz_log(LOG_LOG, "%s%d hits", m_session_str,
+               yaz_log(YLOG_LOG, "%s%d hits", m_session_str,
                        *sr->resultCount);
                if (*sr->resultCount < 0)
                {
@@ -1100,8 +1199,15 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
        }
        if (p && p->which == Z_Records_DBOSD)
        {
+           if (m_backend_type 
+#if HAVE_USEMARCON
+               || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+               )
+               convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
            if (m_marcxml_flag)
-               convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+               convert_to_marcxml(p->u.databaseOrSurDiagnostics,
+                                  m_backend_charset);
            if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
                return 0;
        }
@@ -1167,7 +1273,7 @@ int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
     const char *apdu_name_tmp = apdu_name(apdu);
     int r = send_Z_PDU(apdu, &len);
     if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
-       yaz_log (LOG_LOG, "%sSending %s to %s %d bytes",
+       yaz_log (YLOG_LOG, "%sSending %s to %s %d bytes",
                 get_session_str(),
                 apdu_name_tmp, get_hostname(), len);
     m_bytes_sent += len;
@@ -1182,7 +1288,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
        int toget = *pr->numberOfRecordsRequested;
        int start = *pr->resultSetStartPoint;
 
-       yaz_log(LOG_LOG, "%sPresent %s %d+%d", m_session_str,
+       yaz_log(YLOG_LOG, "%sPresent %s %d+%d", m_session_str,
                pr->resultSetId, start, toget);
 
        if (*m_parent->m_optimize == '0')
@@ -1208,11 +1314,16 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
                return 0;
            }
            Z_NamePlusRecordList *npr;
+#if 0
+           yaz_log(YLOG_LOG, "%sCache lookup %d+%d syntax=%s",
+                   m_session_str, start, toget, yaz_z3950oid_to_str(
+                       pr->preferredRecordSyntax, &oclass));
+#endif
            if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
                                          pr->preferredRecordSyntax,
                                          pr->recordComposition))
            {
-               yaz_log (LOG_LOG, "%sReturned cached records for present request", 
+               yaz_log (YLOG_LOG, "%sReturned cached records for present request", 
                         m_session_str);
                Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
                new_apdu->u.presentResponse->referenceId = pr->referenceId;
@@ -1246,7 +1357,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
 
     char query_str[120];
     this_query->print(query_str, sizeof(query_str)-1);
-    yaz_log(LOG_LOG, "%sSearch %s", m_session_str, query_str);
+    yaz_log(YLOG_LOG, "%sSearch %s", m_session_str, query_str);
 
     if (*m_parent->m_optimize != '0' &&
        m_client->m_last_ok && m_client->m_last_query &&
@@ -1276,7 +1387,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
            if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
                                          sr->preferredRecordSyntax, comp))
            {
-               yaz_log (LOG_LOG, "%sReturned cached records for medium set",
+               yaz_log (YLOG_LOG, "%sReturned cached records for medium set",
                         m_session_str);
                Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
                new_apdu->u.searchResponse->referenceId = sr->referenceId;
@@ -1301,7 +1412,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
            {
                // medium Set
                // send present request (medium size)
-               yaz_log (LOG_LOG, "%sOptimizing search for medium set",
+               yaz_log (YLOG_LOG, "%sOptimizing search for medium set",
                         m_session_str);
 
                Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
@@ -1319,7 +1430,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
            m_client->m_last_resultCount <= 0)
        {
             // large set. Return pseudo-search response immediately
-           yaz_log (LOG_LOG, "%sOptimizing search for large set",
+           yaz_log (YLOG_LOG, "%sOptimizing search for large set",
                     m_session_str);
            Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
            new_apdu->u.searchResponse->referenceId = sr->referenceId;
@@ -1347,7 +1458,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
            if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
                                          sr->preferredRecordSyntax, comp))
            {
-               yaz_log (LOG_LOG, "%sReturned cached records for small set",
+               yaz_log (YLOG_LOG, "%sReturned cached records for small set",
                         m_session_str);
                Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
                new_apdu->u.searchResponse->referenceId = sr->referenceId;
@@ -1370,7 +1481,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
            }
            else
            {
-               yaz_log (LOG_LOG, "%sOptimizing search for small set",
+               yaz_log (YLOG_LOG, "%sOptimizing search for small set",
                         m_session_str);
                Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
                Z_PresentRequest *pr = new_apdu->u.presentRequest;
@@ -1417,7 +1528,7 @@ void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
     m_bytes_recv += len;
     
     if (m_log_mask & PROXY_LOG_REQ_CLIENT)
-       yaz_log (LOG_LOG, "%sReceiving %s from client %d bytes",
+       yaz_log (YLOG_LOG, "%sReceiving %s from client %d bytes",
                 m_session_str, gdu_name(apdu), len);
 
     if (m_bw_hold_PDU)     // double incoming PDU. shutdown now.
@@ -1449,9 +1560,10 @@ void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
            reduce = (reduce > nreduce) ? reduce : nreduce;
        }
     }
+    m_http_version = 0;
     if (reduce)  
     {
-       yaz_log(LOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+       yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
                m_session_str, reduce, bw_total, pdu_total,
                m_bw_max, m_pdu_max);
        
@@ -1512,17 +1624,17 @@ Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
        Z_SearchRequest *sr = apdu->u.searchRequest;
        char *addinfo = 0;
        
-       yaz_log(LOG_LOG, "%sCQL: %s", m_session_str,
+       yaz_log(YLOG_LOG, "%sCQL: %s", m_session_str,
                sr->query->u.type_104->u.cql);
 
        int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
                                          &rpnquery, odr_encode(),
                                          &addinfo);
        if (r == -3)
-           yaz_log(LOG_LOG, "%sNo CQL to RPN table", m_session_str);
+           yaz_log(YLOG_LOG, "%sNo CQL to RPN table", m_session_str);
        else if (r)
        {
-           yaz_log(LOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
+           yaz_log(YLOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
            Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
 
            new_apdu->u.searchResponse->referenceId = sr->referenceId;
@@ -1593,12 +1705,24 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
            rc = &rc_temp;
        }
 
+       if (sr->preferredRecordSyntax)
+       {
+           struct oident *ent;
+           ent = oid_getentbyoid(sr->preferredRecordSyntax);
+           m_frontend_type = ent->value;
+       }
+       else
+           m_frontend_type = VAL_NONE;
+
        char *stylesheet_name = 0;
        if (cfg)
            err = cfg->check_syntax(odr_encode(),
                                    m_default_target,
                                    sr->preferredRecordSyntax, rc,
-                                   &addinfo, &stylesheet_name, &m_schema);
+                                   &addinfo, &stylesheet_name, &m_schema,
+                                   &m_backend_type, &m_backend_charset,
+                                    &m_usemarcon_ini_stage1,
+                                   &m_usemarcon_ini_stage2);
        if (stylesheet_name)
        {
            m_parent->low_socket_close();
@@ -1616,8 +1740,19 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
        }
        if (err == -1)
        {
-           sr->preferredRecordSyntax =
-               yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN, VAL_USMARC);
+           sr->smallSetElementSetNames = 0;
+           sr->mediumSetElementSetNames = 0;
+           if (m_backend_type)
+           {
+               
+               sr->preferredRecordSyntax =
+                   yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
+                                       m_backend_type);
+           }
+           else
+               sr->preferredRecordSyntax =
+                   yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
+                                          VAL_USMARC);
            m_marcxml_flag = 1;
        }
        else if (err)
@@ -1633,6 +1768,11 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
            
            return 0;
        }
+       else if (m_backend_type)
+       {
+           sr->preferredRecordSyntax =
+               yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
+       }
     }
     else if (apdu->which == Z_APDU_presentRequest)
     {
@@ -1641,12 +1781,25 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
        char *addinfo = 0;
        Yaz_ProxyConfig *cfg = check_reconfigure();
 
+       if (pr->preferredRecordSyntax)
+       {
+           struct oident *ent;
+           ent = oid_getentbyoid(pr->preferredRecordSyntax);
+           m_frontend_type = ent->value;
+       }
+       else
+           m_frontend_type = VAL_NONE;
+
        char *stylesheet_name = 0;
        if (cfg)
            err = cfg->check_syntax(odr_encode(), m_default_target,
                                    pr->preferredRecordSyntax,
                                    pr->recordComposition,
-                                   &addinfo, &stylesheet_name, &m_schema);
+                                   &addinfo, &stylesheet_name, &m_schema,
+                                   &m_backend_type, &m_backend_charset,
+                                    &m_usemarcon_ini_stage1,
+                                   &m_usemarcon_ini_stage2
+                                   );
        if (stylesheet_name)
        {
            m_parent->low_socket_close();
@@ -1664,8 +1817,18 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
        }
        if (err == -1)
        {
-           pr->preferredRecordSyntax =
-               yaz_oidval_to_z3950oid(odr_decode(), CLASS_RECSYN, VAL_USMARC);
+           pr->recordComposition = 0;
+           if (m_backend_type)
+           {
+               
+               pr->preferredRecordSyntax =
+                   yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
+                                       m_backend_type);
+           }
+           else
+               pr->preferredRecordSyntax =
+                   yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
+                                          VAL_USMARC);
            m_marcxml_flag = 1;
        }
        else if (err)
@@ -1682,6 +1845,11 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
            
            return 0;
        }
+       else if (m_backend_type)
+       {
+           pr->preferredRecordSyntax =
+               yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN, m_backend_type);
+       }
     }
     return apdu;
 }
@@ -1697,6 +1865,89 @@ Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
     return esn;
 }
 
+void Yaz_Proxy::srw_get_client(const char *db, const char **backend_db)
+{
+    const char *t = 0;
+    Yaz_ProxyConfig *cfg = check_reconfigure();
+    if (cfg)
+       t = cfg->get_explain_name(db, backend_db);
+
+    if (m_client && m_default_target && t && strcmp(m_default_target, t))
+    {
+       releaseClient();
+    }
+    
+    if (t)
+    {
+       xfree(m_default_target);
+       m_default_target = xstrdup(t);
+    }
+}
+
+int Yaz_Proxy::file_access(Z_HTTP_Request *hreq)
+{
+    yaz_log(YLOG_LOG, "file_access");
+    if (strcmp(hreq->method, "GET"))
+       return 0;
+    struct stat sbuf;
+    if (hreq->path[0] != '/')
+    {
+       yaz_log(YLOG_WARN, "Path != /");
+       return 0;
+    }
+    const char *cp = hreq->path;
+    while (*cp)
+    {
+       if (*cp == '/' && strchr("/.", cp[1]))
+           return 0;
+       cp++;
+    }
+    const char *fname = hreq->path+1;
+    if (stat(fname, &sbuf))
+    {
+       yaz_log(YLOG_WARN, "stat %s failed", fname);
+       return 0;
+    }
+    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+       return 0;
+    if (sbuf.st_size > (off_t) 1000000)
+       return 0;
+
+    ODR o = odr_encode();
+    Yaz_ProxyConfig *cfg = check_reconfigure();
+    const char *ctype = cfg->check_mime_type(fname);
+    Z_GDU *gdu = z_get_HTTP_Response(o, 200);
+    Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+    if (m_http_version)
+       hres->version = odr_strdup(o, m_http_version);
+    z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+    if (m_http_keepalive)
+        z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+    else
+       timeout(0);
+
+    hres->content_len = sbuf.st_size;
+    hres->content_buf = (char*) odr_malloc(o, hres->content_len);
+    FILE *f = fopen(fname, "rb");
+    if (f)
+    {
+       fread(hres->content_buf, 1, hres->content_len, f);
+       fclose(f);
+    }
+    else
+    {
+       return 0;
+    }
+    if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+    {
+       yaz_log (YLOG_LOG, "%sSending file %s to client", m_session_str,
+                fname);
+    }
+    int len;
+    send_GDU(gdu, &len);
+    return 1;
+}
+       
 void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
 {
     if (m_s2z_odr_init)
@@ -1736,10 +1987,15 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
     char *charset = 0;
     Z_SRW_diagnostic *diagnostic = 0;
     int num_diagnostic = 0;
-    if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
-                      &charset) == 0
-       || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
-                         &charset, &diagnostic, &num_diagnostic) == 0)
+
+    if (file_access(hreq))
+    {
+       return;
+    }
+    else if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+                           &charset) == 0
+            || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+                              &charset, &diagnostic, &num_diagnostic) == 0)
     {
        m_s2z_odr_init = odr_createmem(ODR_ENCODE);
        m_s2z_odr_search = odr_createmem(ODR_ENCODE);
@@ -1754,6 +2010,9 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
        {
            Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
 
+           const char *backend_db = srw_req->database;
+           srw_get_client(srw_req->database, &backend_db);
+
            m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
            // recordXPath unsupported.
            if (srw_req->recordXPath)
@@ -1804,7 +2063,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
            z_searchRequest->databaseNames = (char**)
                odr_malloc(m_s2z_odr_search, sizeof(char *));
            z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
-                                                          srw_req->database);
+                                                          backend_db);
            
            // query transformation
            Z_Query *query = (Z_Query *)
@@ -1839,8 +2098,8 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
                    const char *pqf_msg;
                    size_t off;
                    int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
-                   yaz_log(LOG_LOG, "%*s^\n", off+4, "");
-                   yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
+                   yaz_log(YLOG_LOG, "%*s^\n", off+4, "");
+                   yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
                    
                    send_to_srw_client_error(10, 0);
                    return;
@@ -1931,6 +2190,9 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
        {
            Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
 
+           const char *backend_db = srw_req->database;
+           srw_get_client(srw_req->database, &backend_db);
+
            m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
 
            // save stylesheet
@@ -1989,10 +2251,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
            send_to_srw_client_error(4, 0);
         }
     }
-    int len = 0;
-    Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);
-    timeout(0);
-    send_GDU(p, &len);
+    send_http_response(400);
 }
 
 void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
@@ -2024,21 +2283,29 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
     m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
     if (!m_client)
     {
-       delete this;
-       return;
+       if (m_http_version)
+       {
+           send_http_response(404);
+           return;
+       }
+       else
+       {
+           delete this;
+           return;
+       }
     }
     m_client->m_server = this;
 
     if (apdu->which == Z_APDU_initRequest)
     {
        if (apdu->u.initRequest->implementationId)
-           yaz_log(LOG_LOG, "%simplementationId: %s",
+           yaz_log(YLOG_LOG, "%simplementationId: %s",
                    m_session_str, apdu->u.initRequest->implementationId);
        if (apdu->u.initRequest->implementationName)
-           yaz_log(LOG_LOG, "%simplementationName: %s",
+           yaz_log(YLOG_LOG, "%simplementationName: %s",
                    m_session_str, apdu->u.initRequest->implementationName);
        if (apdu->u.initRequest->implementationVersion)
-           yaz_log(LOG_LOG, "%simplementationVersion: %s",
+           yaz_log(YLOG_LOG, "%simplementationVersion: %s",
                    m_session_str, apdu->u.initRequest->implementationVersion);
        if (m_initRequest_apdu == 0)
        {
@@ -2122,9 +2389,9 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
        return;
     }
 
-    // delete other info part from PDU before sending to target
+    // delete other info construct completely if 0 elements
     get_otherInfoAPDU(apdu, &oi);
-    if (oi)
+    if (*oi && (*oi)->num_elements == 0)
         *oi = 0;
 
     if (apdu->which == Z_APDU_presentRequest &&
@@ -2150,8 +2417,10 @@ void Yaz_Proxy::connectNotify()
 {
 }
 
-void Yaz_Proxy::shutdown()
+void Yaz_Proxy::releaseClient()
 {
+    xfree(m_proxyTarget);
+    m_proxyTarget = 0;
     m_invalid_session = 0;
     // only keep if keep_alive flag is set...
     if (m_client && 
@@ -2159,39 +2428,45 @@ void Yaz_Proxy::shutdown()
        m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
        m_client->m_waiting == 0)
     {
-        yaz_log(LOG_LOG, "%sShutdown (client to proxy) keepalive %s",
+        yaz_log(YLOG_LOG, "%sShutdown (client to proxy) keepalive %s",
                 m_session_str,
                  m_client->get_hostname());
-       yaz_log(LOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+       yaz_log(YLOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
                m_session_str, m_client->m_pdu_recv,
                m_client->m_bytes_sent + m_client->m_bytes_recv,
                m_keepalive_limit_bw, m_keepalive_limit_pdu);
         assert (m_client->m_waiting != 2);
        // Tell client (if any) that no server connection is there..
        m_client->m_server = 0;
-       m_invalid_session = 0;
+       m_client = 0;
     }
     else if (m_client)
     {
-        yaz_log (LOG_LOG, "%sShutdown (client to proxy) close %s",
+        yaz_log (YLOG_LOG, "%sShutdown (client to proxy) close %s",
                 m_session_str,
                  m_client->get_hostname());
         assert (m_client->m_waiting != 2);
        delete m_client;
+       m_client = 0;
     }
     else if (!m_parent)
     {
-        yaz_log (LOG_LOG, "%sshutdown (client to proxy) bad state",
+        yaz_log (YLOG_LOG, "%sshutdown (client to proxy) bad state",
                 m_session_str);
         assert (m_parent);
     }
     else 
     {
-        yaz_log (LOG_LOG, "%sShutdown (client to proxy)",
+        yaz_log (YLOG_LOG, "%sShutdown (client to proxy)",
                 m_session_str);
     }
     if (m_parent)
        m_parent->pre_init();
+}
+
+void Yaz_Proxy::shutdown()
+{
+    releaseClient();
     delete this;
 }
 
@@ -2204,7 +2479,7 @@ const char *Yaz_ProxyClient::get_session_str()
 
 void Yaz_ProxyClient::shutdown()
 {
-    yaz_log (LOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
+    yaz_log (YLOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
             get_hostname());
     delete m_server;
     delete this;
@@ -2213,7 +2488,7 @@ void Yaz_ProxyClient::shutdown()
 void Yaz_Proxy::failNotify()
 {
     inc_request_no();
-    yaz_log (LOG_LOG, "%sConnection closed by client",
+    yaz_log (YLOG_LOG, "%sConnection closed by client",
             get_session_str());
     shutdown();
 }
@@ -2222,7 +2497,7 @@ void Yaz_ProxyClient::failNotify()
 {
     if (m_server)
        m_server->inc_request_no();
-    yaz_log (LOG_LOG, "%sConnection closed by target %s", 
+    yaz_log (YLOG_LOG, "%sConnection closed by target %s", 
             get_session_str(), get_hostname());
     shutdown();
 }
@@ -2231,7 +2506,7 @@ void Yaz_ProxyClient::connectNotify()
 {
     const char *s = get_session_str();
     const char *h = get_hostname();
-    yaz_log (LOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
+    yaz_log (YLOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
             m_target_idletime);
     timeout(m_target_idletime);
     if (!m_server)
@@ -2294,6 +2569,7 @@ void Yaz_Proxy::pre_init()
     int keepalive_limit_bw, keepalive_limit_pdu;
     int pre_init;
     const char *cql2rpn = 0;
+    const char *authentication = 0;
 
     Yaz_ProxyConfig *cfg = check_reconfigure();
 
@@ -2311,7 +2587,8 @@ void Yaz_Proxy::pre_init()
                                          &keepalive_limit_bw,
                                          &keepalive_limit_pdu,
                                          &pre_init,
-                                         &cql2rpn) ; i++)
+                                         &cql2rpn,
+                                         &authentication) ; i++)
     {
        if (pre_init)
        {
@@ -2341,7 +2618,7 @@ void Yaz_Proxy::pre_init()
                            other++;
                    }
                }
-               yaz_log(LOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
+               yaz_log(YLOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
                        "sparew=%d preinit=%d",m_session_str,
                        name, zurl_in_use[j], in_use, other,
                        spare, spare_waiting, pre_init);
@@ -2396,7 +2673,7 @@ void Yaz_Proxy::timeoutNotify()
        {
            inc_request_no();
 
-           yaz_log (LOG_LOG, "%sTimeout (client to proxy)", m_session_str);
+           yaz_log (YLOG_LOG, "%sTimeout (client to proxy)", m_session_str);
            shutdown();
        }
     }
@@ -2418,7 +2695,7 @@ void Yaz_ProxyClient::timeoutNotify()
     if (m_server)
        m_server->inc_request_no();
 
-    yaz_log (LOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
+    yaz_log (YLOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
             get_hostname());
     m_waiting = 1;
     m_root->pre_init();
@@ -2508,7 +2785,7 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
     m_pdu_recv++;
     m_waiting = 0;
     if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
-       yaz_log (LOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
+       yaz_log (YLOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
                 apdu_name(apdu), get_hostname(), len);
     if (apdu->which == Z_APDU_initResponse)
     {
@@ -2623,7 +2900,7 @@ int Yaz_Proxy::server(const char *addr)
     int r = Yaz_Z_Assoc::server(addr);
     if (!r)
     {
-       yaz_log(LOG_LOG, "%sStarted proxy " 
+       yaz_log(YLOG_LOG, "%sStarted proxy " 
 #ifdef VERSION
            VERSION 
 #endif