/**************************************************************************** * Copyright (C) 2003-2008 by Albert Astals Cid * * aacid@kde.org * * * * 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. * ****************************************************************************/ #include "tdeio_gopher.h" #include #include #include #include #include #include #include #include #include #include using namespace TDEIO; extern "C" { int KDE_EXPORT kdemain( int argc, char **argv ) { TDEInstance instance( "tdeio_gopher" ); if (argc != 4) { fprintf(stderr, "Usage: tdeio_gopher protocol domain-socket1 domain-socket2\n"); exit(-1); } GopherProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); return 0; } } /* gopher */ GopherProtocol::GopherProtocol(const TQCString &pool_socket, const TQCString &app_socket) : TCPSlaveBase(70, "gopher", pool_socket, app_socket) { } void GopherProtocol::get(const KURL& url ) { // gopher urls are // gopher://:/ // // where is one of // // // %09 // %09%09 int port; TQChar type; TQString path(url.path()); TQString query(url.query()); // determine the type if (path != "/" && path != "") type = path[1]; else type = '1'; // determine the port if (url.port() > 0) port = url.port(); else port = 70; setBlockConnection(true); // connect to the host if (!connectToHost(url.host(), port)) return; if (type == '7' && query.isNull()) { closeDescriptor(); handleSearch(url.host(), path, port); } else { int i, bytes; char aux[10240]; TQBuffer received; received.open(IO_WriteOnly); infoMessage(i18n("Connecting to %1...").arg(url.host())); infoMessage(i18n("%1 contacted. Retrieving data...").arg(url.host())); bytes = 0; // send the selector path.remove(0, 2); write(path.latin1(), path.length()); write(query.latin1(), query.length()); write("\r\n", 2); // read the data while((i = read(aux, 10240)) > 0) { bytes += i; received.writeBlock(aux, i); processedSize(bytes); infoMessage(i18n("Retrieved %1 bytes from %2...").arg(bytes).arg(url.host())); } if (type == '1' || type =='7') { processDirectory(received.buffer().data(), url.host(), url.path()); } else { KMimeType::Ptr result = KMimeType::findByContent(received.buffer()); mimeType(result->name()); data(received.buffer()); } closeDescriptor(); } finished(); } void GopherProtocol::processDirectory(const TQString &received_str, const TQString &host, const TQString &path) { TQString received(received_str); TQString pathToShow; if (path == "/" || path == "/1") { pathToShow = ""; } else { pathToShow = path; } mimeType("text/html"); TQString info; TQString show("\n" "\n\t\n\t\t"); show += host.utf8(); show += pathToShow.utf8(); show += TQString("\n\t\t\n" "\t\t\n\t\n\t\n\t\t

"); show += host.utf8(); show += pathToShow.utf8(); show += "

\n"; int i, remove; findLine(received, &i, &remove); while(i != -1) { processDirectoryLine(received.left(i), show, info); received.remove(0, i + remove); findLine(received, &i, &remove); } show += "\t\n\n"; TQByteArray showdata; showdata.duplicate(show.utf8(), show.length()); data(showdata); } void GopherProtocol::processDirectoryLine(const TQString &d, TQString &show, TQString &info) { // gopher <\r><\n> // gopher+ <\r><\n> int i; TQString data(d); TQString type = data.left(1); data.remove(0, 1); i = data.find("\t"); TQString name = data.left(i); data.remove(0, i + 1); i = data.find("\t"); TQString url = data.left(i); data.remove(0, i + 1); i = data.find("\t"); TQString server = data.left(i); data.remove(0, i + 1); TQString port = parsePort(data); if (type == "i") { if (!info.isEmpty()) info.append("\n"); info.append(name); } else { if (!info.isEmpty()) { show.append("\t\t
"); show.append(info); show.append("
\n"); info = ""; } // it's the final line, ignore it if (type == ".") return; // those are the standard gopher types defined in the rfc // 0 Item is a file // 1 Item is a directory // 2 Item is a CSO phone-book server // 3 Error // 4 Item is a BinHexed Macintosh file. // 5 Item is DOS binary archive of some sort. Client must read until the TCP connection closes. Beware. // 6 Item is a UNIX uuencoded file. // 7 Item is an Index-Search server. // 8 Item points to a text-based telnet session. // 9 Item is a binary file! Client must read until the TCP connection closes. Beware. // + Item is a redundant server // T Item points to a text-based tn3270 session. // g Item is a GIF format graphics file. // I Item is some kind of image file. Client decides how to display. show.append("\t\t\t
"); // support the non-standard extension for URL to external sites // in this case, url begins with 'URL:' TQString finalUrl; TQString iconUrl; if (url.startsWith("URL:")) { finalUrl = url.mid(4); iconUrl = finalUrl; } else { finalUrl = "gopher://" + server; if (port != "70") { finalUrl.append(":"); finalUrl.append(port); } finalUrl.append('/' + type + url); iconUrl = url; } show.append("\t\t\t\t"); addIcon(type, iconUrl, show); show.append(name); show.append("
\n"); show.append("\t\t\t
"); } } TQString GopherProtocol::parsePort(TQString &received) { uint i = 0; TQString port; bool found = false; TQChar c; while (!found && i < received.length()) { c = received[i]; if (c.isDigit()) i++; else found = true; } port = received.left(i); received.remove(0, i); return port; } void GopherProtocol::findLine(const TQString &received, int *i, int *remove) { // it's not in the rfc but most servers don't follow the spec // find lines ending only in \n and in \r\n int aux, aux2; aux = received.find("\r\n"); aux2 = received.find("\n"); if (aux == -1) { *i = aux2; *remove = 1; } else { if (aux2 < aux) { *remove = 1; *i = aux2; } else { *remove = 2; *i = aux; } } } void GopherProtocol::handleSearch(const TQString &host, const TQString &path, int port) { TQString sPort; if (port != 70) sPort = ':' + TQString::number(port); mimeType("text/html"); TQString show("\n" "\n\t\n\t\t"); show += host.utf8(); show += path.utf8(); show += "\n\t\t\n" "\t\t\n\t\n\t\n\t\t

"; show.append(host.utf8()); show.append(path.utf8()); show += "

\n\t\t"; show += i18n("Enter a search term:").utf8(); show += "
\n\t\t\n\t\t\n\t\n\n"; TQByteArray showdata; showdata.duplicate(show.utf8(), show.length()); data(showdata); } void GopherProtocol::addIcon(const TQString &type, const TQString &url, TQString &show) { TQString icon; if (type == "1") icon = "inode-directory.png"; else if (type == "3") icon = "dialog-error.png"; else if (type == "7") icon = "system-search.png"; else if (type == "g") icon = "image-gif.png"; else if (type == "I") icon = "image-x-generic.png"; else { KMimeType::Ptr mime = KMimeType::findByURL(KURL(url), 0, false, true); icon = mime->icon(TQString::null, false); } TQFile file(m_iconLoader.iconPath(icon, -16)); file.open(IO_ReadOnly); TQByteArray ba = file.readAll(); show.append(" "); }