Logo Search packages:      
Sourcecode: kbib version File versions  Download package

z3950connection.cpp

//
// C++ Implementation: z3950connection
//
// Description:
//
//
// Author: Thach Nguyen <thach.nguyen@rmit.edu.au>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "z3950connection.h"
#include "searcher.h"
#include "z3950searcher.h"
#include <kapplication.h>
#include <iostream>
#include <qstring.h>
#include <klocale.h>

Z3950Connection::Z3950Connection(Z3950Searcher *searcher,
                                 const QString& host,
                                 uint port,
                                 const QString& dbname,
                                 const QString& sourceCharSet,
                                 const QString& syntax,
                                 const QString& esn)
        : QThread()
{
    m_connected = false;
    m_aborted = false;
    m_waitingRetrieveRange = false;
    m_searcher = searcher;
    m_host = QDeepCopy<QString>(host);
    m_port = port;
    m_dbname = QDeepCopy<QString>(dbname);
    m_sourceCharSet = QDeepCopy<QString>(sourceCharSet.left(64));
    m_syntax = QDeepCopy<QString>(syntax);
    m_esn = QDeepCopy<QString>(esn);
#if HAVE_YAZ
      conn = 0;
#endif
}


Z3950Connection::~Z3950Connection()
{
    m_connected = false;
#if HAVE_YAZ
      if (conn)
        delete conn;
#endif
}

void Z3950Connection::setQuery(const QString& query_)
{
    m_pqn = QDeepCopy<QString>(query_);
}

void Z3950Connection::setUserPassword(const QString& user_, const QString& pword_)
{
    m_user = QDeepCopy<QString>(user_);
    m_password = QDeepCopy<QString>(pword_);
}

void Z3950Connection::run()
{
    m_aborted = false;
      
#if HAVE_YAZ

    if(!makeConnection())
    {
        done();
        return;
    }

//    std::cerr << "Starting quering ... \n";
//    std::cerr << "Syntax " << m_syntax.latin1() << "\n";
//    std::cerr << "Element set name " << m_esn.latin1() << "\n";
//    std::cerr << "Query " << m_pqn.latin1() << "\n";
      QString errMsg;
      bool err = false;
    try {
        //Set preferredRecordSyntax and ElementSetName
        if (m_syntax == QString("mods") )
        {
         
                  conn->option("preferredRecordSyntax", "xml");
            conn->option("elementSetName", "mods");

        }
        else
        {
           
                  conn->option("preferredRecordSyntax", m_syntax.latin1());
            conn->option("elementSetName", m_esn.latin1());
    
            }
            
        ZOOM::resultSet rs(*conn, ZOOM::prefixQuery(m_pqn.latin1()));
        
            if(m_aborted)
        {
            done();
            return;
        }

       const size_t size = rs.size();
       if (size <1)
        {
                  KApplication::postEvent((QObject*)m_searcher, new Z3950QueryResult(size) );
                  done(i18n("No reference was found."), 1);
                  return;     
            }
            else{
                  startRange = 0;
                  endRange = 0;
//                std::cerr << "found " << size << " records:\n";
            KApplication::postEvent((QObject*)m_searcher, new Z3950QueryResult(size) );
            m_waitingRetrieveRange = true;

            while(m_searcher->isWaitingRetrieveRange() )
            {
            }

                  if (startRange > 0 && endRange > 0){
            for (size_t i = startRange; i <= endRange && !m_aborted; ++i)
            {
                const ZOOM::record rec(rs,i-1);
                QString data;
                        if(m_syntax == QString::fromLatin1("mods"))
                {
                    data = toString((rec.rawdata()).c_str());
                }
                        else if(m_syntax == QString::fromLatin1("grs-1")) { // grs-1
                              data = toString((rec.render()).c_str());
                        }
                else
                {
                    data = toXML((rec.rawdata()).c_str(), m_sourceCharSet);
                }
                //Signal searcher the data is available
                KApplication::postEvent((QObject*)m_searcher, new Z3950ResultFound(data) );
            }
                  }
        }


   } catch (ZOOM::systemException &e) {
        std::cerr << "System error " << e.errcode() << " (" << e.errmsg() << ")" << std::endl;
            errMsg = i18n("System error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
            err = true;
            
    }
      catch (ZOOM::bib1Exception e)
    {
        std::cerr << "BIB-1 error " <<
        e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << std::endl;
            errMsg = i18n("BIB-1 error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
            err = true;
    }
      catch (ZOOM::queryException &e)
    {
        std::cerr << "Query error " <<
        e.errcode() << " (" << e.errmsg() << "): " << e.addinfo() << std::endl;
            errMsg = i18n("Query error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
            err = true;
    }
      catch (ZOOM::exception &e)
    {
        std::cerr << "Error " <<
        e.errcode() << " (" << e.errmsg() << ")" << std::endl;
            errMsg = i18n("Connection error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
            err = true;
    }
      
      if (err){
            done(errMsg, 0);
            return;     
      }
      
      

#endif
    done();

}

bool Z3950Connection::makeConnection()
{
    if(m_connected)
    {
        return true;
    }
#if HAVE_YAZ
      QString errMsg;
    try    {
        conn = new ZOOM::connection(m_host.latin1(), m_port);
            conn->option("databaseName", m_dbname.latin1());
        if (!m_user.isEmpty())
            conn->option("user",m_user.latin1() );
        if (!m_password.isEmpty())
            conn->option("password",m_password.latin1() );
      m_connected = true;
    }
      catch (ZOOM::systemException &e)
    {
        //std::cerr << "System error " << e.errcode() << " (" << e.errmsg() << ")" << endl;
      errMsg = i18n("System error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
        m_connected = false;
    }

      catch (ZOOM::exception &e)
    {
        //std::cerr << "Error " << e.errcode() << " (" << e.errmsg() << ")" << std::endl;
            errMsg = i18n("Connection error %1: %2").arg(e.errcode()).arg( (e.errmsg() ).c_str() ); 
        m_connected = false;
    }
    if (!m_connected){
        std::cerr << errMsg.latin1() << "\n";
            done(errMsg, 0);
            return false;
    }

#endif
    m_connected = true;
    return true;

}

inline
QCString Z3950Connection::toCString(const QString& text_)
{
    return iconv(text_.utf8(), QString::fromLatin1("utf-8"), m_sourceCharSet);
}


inline
QString Z3950Connection::toString(const QCString& text_)
{
    return QString::fromUtf8(iconv(text_, m_sourceCharSet, QString::fromLatin1("utf-8")));
}

QCString Z3950Connection::iconv(const QCString& text_, const QString& fromCharSet_, const QString& toCharSet_)
{
//    std::cerr << "Converting from " << fromCharSet_.latin1() << " to " << toCharSet_.latin1() << "..............\n";
#if HAVE_YAZ
    if(text_.isEmpty())
    {
        return text_;
    }

    if(fromCharSet_ == toCharSet_)
    {
        return text_;
    }

    yaz_iconv_t cd = yaz_iconv_open(toCharSet_.latin1(), fromCharSet_.latin1());
    if(!cd)
    {
        /*    // maybe it's iso 5426, which we sorta support
              QString charSetLower = fromCharSet_.lower();
              charSetLower.remove('-').remove(' ');
              if(charSetLower == Latin1Literal("iso5426")) {
                    return iconv(Iso5426Converter::toUtf8(text_).utf8(), QString::fromLatin1("utf-8"), toCharSet_);
              } else if(charSetLower == Latin1Literal("iso6937")) {
                    return iconv(Iso6937Converter::toUtf8(text_).utf8(), QString::fromLatin1("utf-8"), toCharSet_);
              }
              kdWarning() << "Z3950Fetcher::iconv() - conversion from " << fromCharSet_
                          << " to " << toCharSet_ << " is unsupported" << endl;
        */
        return text_;
    }

    const char* input = text_;
    size_t inlen = text_.length();

    size_t outlen = 2 * inlen;  // this is enough, right?
    char* result0 = new char[outlen];
    char* result = result0;

    int r = yaz_iconv(cd, const_cast<char**>(&input), &inlen, &result, &outlen);
    if(r <= 0)
    {
        std::cerr << "Z3950Fetcher::iconv() - can't decode buffer" << endl;
        return text_;
    }

    // length is pointer difference
    size_t len = result - result0;

    QCString output = QCString(result0, len+1);
    yaz_iconv_close(cd);
    delete result0;
    return output;
#endif
    return text_;
}

QString Z3950Connection::toXML(const QCString& marc_, const QString& charSet_)
{
#if HAVE_YAZ
    if(marc_.isEmpty())
    {
        std::cerr << "Z3950Searcher::toXML() - empty string" << endl;
        return QString::null;
    }

    yaz_iconv_t cd = yaz_iconv_open("utf-8", charSet_.latin1());
    if(!cd)
    {
        return QString::null;
    }

    yaz_marc_t mt = yaz_marc_create();
    yaz_marc_iconv(mt, cd);
    yaz_marc_xml(mt, YAZ_MARC_MARCXML);

    // first 5 bytes are length
    bool ok;
#if YAZ_VERSION_3_0_0   
    size_t len;
      const char* result;
#else
      int len;
      char* result;
#endif      
      len = marc_.left(5).toInt(&ok);
    if(ok && (len < 25 || len > 100000))
    {
        std::cerr << "Z3950Searcher::toXML() - bad length: " << (ok ? len : -1) << endl;
        return QString::null;
    }

    
    int r = yaz_marc_decode_buf(mt, marc_, -1, &result, &len);
    if(r <= 0)
    {
        std::cerr << "Z3950Searcher::toXML() - can't decode buffer" << endl;
        return QString::null;
    }

    QString output = QString::fromLatin1("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    output += QString::fromUtf8(QCString(result, len+1), len+1);
    yaz_iconv_close(cd);
    yaz_marc_destroy(mt);

    return output;
#else // no yaz
    return QString::null;
#endif
}

void Z3950Connection::done() {
      kapp->postEvent(m_searcher, new Z3950ConnectionDone());
}

void Z3950Connection::done(const QString& msg_, int type_) {
      if(m_aborted) {
            kapp->postEvent(m_searcher, new Z3950ConnectionDone());
      } else {
            kapp->postEvent(m_searcher, new Z3950ConnectionDone(msg_, type_));
      }
}

void Z3950Connection::retrieveRange(unsigned int min, unsigned int max)
{
    startRange = min;
    endRange = max;
    m_waitingRetrieveRange = false;
}
            

Generated by  Doxygen 1.6.0   Back to index