/* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "chm.h" using namespace KIO; extern "C" { int kdemain( int argc, char **argv ) { KInstance instance( "kio_chm" ); kdDebug() << "*** Starting kio_chm " << endl; if (argc != 4) { kdDebug() << "Usage: kio_chm protocol domain-socket1 domain-socket2" << endl; exit(-1); } ChmProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); kdDebug() << "*** kio_chm Done" << endl; return 0; } } ChmProtocol::ChmProtocol(const QCString &pool_socket, const QCString &app_socket) : SlaveBase("kio_chm", pool_socket, app_socket) { kdDebug() << "ChmProtocol::ChmProtocol()" << endl; } /* ---------------------------------------------------------------------------------- */ ChmProtocol::~ChmProtocol() { kdDebug() << "ChmProtocol::~ChmProtocol()" << endl; } /* ---------------------------------------------------------------------------------- */ void ChmProtocol::get( const KURL& url ) { /** When :catalog is appended to the end, a plain-text representation of the catalog * is given out where each entry consists of four lines, an integer representing the parent * of the node, an integer representing a node's ID, the Title of the Node, and it's hyperlink. * When :contents is appended, all contained htm- and html-files will be printed, each in a line. */ kdDebug() << "kio_chm::get(const KURL& url) " << url.path() << endl; bool catalog = false; bool contents = false; QString bigpath = url.path(); if(bigpath.endsWith(":catalog")) { catalog = true; int len = QString(":catalog").length(); bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end } if(bigpath.endsWith(":contents")) { contents = true; int len = QString(":contents").length(); bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end } QString path; if ( !checkNewFile( bigpath, path ) ) { error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() ); return; } if (m_dirMap.find(path) == m_dirMap.end()) { error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() ); return; } QByteArray theData; //init.. //added by lucida lucida@users.sf.net QString fname = QString(); QString chmpath = QString(); KTempFile f("",".html"); fname = f.name(); QTextStream *t = f.textStream(); QString firstPage = QString(""); QString m_strIndex = QString(""); QString tmpstr = QString(""); bool m_bIndex = 0; if(contents) { QString output; KURL u = url; ChmDirectoryMap::Iterator it; for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) { u.setPath(bigpath); u.addPath(it.key()); output += u.prettyURL() + "\n"; } data(output.local8Bit()); processedSize(output.length()); finished(); return; } //try get some page to display, if the chm missing index ChmDirectoryMap::Iterator it; for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) { tmpstr.sprintf("%s", it.key().latin1()); if ((m_strIndex == "") && (tmpstr.endsWith(".htm") || tmpstr.endsWith(".html"))) m_strIndex = tmpstr; if ((tmpstr == "/index.htm") || (tmpstr == "/index.html")) { m_strIndex = tmpstr; break; } } m_strIndex.remove(0,1); if (path == "/" || catalog) { bool htmlOutput = !catalog; int offset = m_dirMap["/@contents"].offset; int length = m_dirMap["/@contents"].length; theData.setRawData(&m_contents[offset], length); QString s(theData); QString output; QRegExp object("(.*)", false); object.setMinimal(true); QRegExp nameParam("", false); nameParam.setMinimal(true); QRegExp localParam("", false); localParam.setMinimal(true); QRegExp mergeParam("", false); mergeParam.setMinimal(true); std::stack parents; int counter = 1; int current = 0; int old = 0, pos = 0; parents.push(0); while ((pos = s.find(object, pos)) != -1) { if(htmlOutput) output += s.mid(old, pos - old); if(catalog) { QRegExp ex("
    |
", false); ex.setMinimal(true); QString ms = s.mid(old, pos - old); int pos = 0; while( (pos = ms.find(ex, pos)) != -1) { if(ms.mid(pos, 4) == "
    ") { parents.push(current); } else{ if(parents.empty()){ }else{ current = parents.top(); parents.pop(); } } pos++; } } pos += object.matchedLength(); old = pos; QString obj = object.cap(1); QString name, local; if (obj.find(nameParam) != -1) { name = nameParam.cap(1); if (obj.find(localParam) != -1) { local = localParam.cap(1); //output += "" + name + ""; //added by lucida lucida@users.sf.net if (local != "" && local != "/") { if(!catalog) { output += "" + name + ""; }else{ current = counter; ++counter; KURL u = url; u.setPath(bigpath + local); QString str; output += str.sprintf("%i\n%i\n", parents.top(), current); output += name + "\n" + u.prettyURL() + "\n"; } m_bIndex = 1; if (firstPage == "") firstPage = url.url()+QString::fromLocal8Bit(local.latin1()); } else if(htmlOutput) output += name; } else { if(htmlOutput) output += name; } } if (obj.find(mergeParam) != -1 && htmlOutput) { QString link = mergeParam.cap(1); QString href = link.left(link.find("::")); QString path = m_chmFile.left(m_chmFile.findRev("/") + 1); //output += " (link)"; m_bIndex = 1; output += " (link)"; if (firstPage == "") firstPage = url.url()+QString::fromLocal8Bit(local.latin1()); } } if(htmlOutput) output += s.mid(old); //set left pane //added by lucida, lucida@users.sf.net QString lframe = QString("\n"); lframe += "\n"; if (!m_bIndex) { lframe = ""; firstPage = url.url() + QString::fromLocal8Bit(m_strIndex.latin1()); } theData.resetRawData(&m_contents[offset], length); //KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( output, path ); //kdDebug() << "Emitting mimetype " << result->mimeType() << endl; //mimeType( result->mimeType() ); /* QCString output1 = (QCString)(output.latin1()); data(output1); processedSize(output1.length());*/ //construct the frame //added by lucida lucida@users.sf.net QString framestr = QString("\n"); framestr += lframe; framestr += "\n"; framestr += "\n"; framestr += ""; //write index file //added by lucida lucida@users.sf.net *t << QString::fromLocal8Bit(output.latin1()) << endl; if(catalog) { data(output.local8Bit()); processedSize(output.length()); }else{ data(framestr.local8Bit()); processedSize(framestr.length()); } } else { int offset = m_dirMap[path].offset; int length = m_dirMap[path].length; totalSize(length); theData.setRawData(&m_contents[offset], length); KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( theData, path ); kdDebug() << "Emitting mimetype " << result->mimeType() << endl; mimeType( result->mimeType() ); data(theData); theData.resetRawData(&m_contents[offset], length); processedSize(length); } finished(); } /* --------------------------------------------------------------------------- */ bool ChmProtocol::checkNewFile( QString fullPath, QString& path ) { //kdDebug() << "ChmProtocol::checkNewFile " << fullPath << endl; fullPath = fullPath.replace(QRegExp("::"), ""); // Are we already looking at that file ? if ( !m_chmFile.isEmpty() && fullPath.startsWith(m_chmFile) ) { path = fullPath.mid(m_chmFile.length()).lower(); return true; } kdDebug() << "Need to open a new file" << endl; m_chmFile = ""; // Find where the chm file is in the full path int pos = 0; QString chmFile; path = ""; int len = fullPath.length(); if ( len != 0 && fullPath[ len - 1 ] != '/' ) fullPath += '/'; //kdDebug() << "the full path is " << fullPath << endl; while ( (pos=fullPath.find( '/', pos+1 )) != -1 ) { QString tryPath = fullPath.left( pos ); //kdDebug() << fullPath << " trying " << tryPath << endl; struct stat statbuf; if ( ::stat( QFile::encodeName(tryPath), &statbuf ) == 0 && !S_ISDIR(statbuf.st_mode) ) { chmFile = tryPath; path = fullPath.mid( pos ).lower(); kdDebug() << "fullPath=" << fullPath << " path=" << path << endl; len = path.length(); if ( len > 2 ) { if ( path[ len - 1 ] == '/' ) path.truncate( len - 1 ); } else { path = QString::fromLatin1("/"); } kdDebug() << "Found. chmFile=" << chmFile << " path=" << path << endl; break; } } if ( chmFile.isEmpty() ) { kdDebug() << "ChmProtocol::checkNewFile: not found" << endl; return false; } m_chmFile = chmFile; // Open new file //kdDebug() << "Opening Chm file on " << chmFile << endl; return m_chm.read(chmFile, m_dirMap, m_contents); }