diff options
Diffstat (limited to 'kioslave/fish/fish.cpp')
-rw-r--r-- | kioslave/fish/fish.cpp | 1661 |
1 files changed, 0 insertions, 1661 deletions
diff --git a/kioslave/fish/fish.cpp b/kioslave/fish/fish.cpp deleted file mode 100644 index 3a527e39e..000000000 --- a/kioslave/fish/fish.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -/*************************************************************************** - fish.cpp - a FISH kioslave - ------------------- - begin : Thu Oct 4 17:09:14 CEST 2001 - copyright : (C) 2001-2003 by J�rg Walter - email : jwalt-kde@garni.ch - ***************************************************************************/ - -/*************************************************************************** - * * - * 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, version 2 of the License * - * * - ***************************************************************************/ - -/* - This code contains fragments and ideas from the ftp kioslave - done by David Faure <faure@kde.org>. - - Structure is a bit complicated, since I made the mistake to use - TDEProcess... now there is a lightweight homebrew async IO system - inside, but if signals/slots become available for ioslaves, switching - back to TDEProcess should be easy. -*/ - -#include "config.h" - -#include <tqcstring.h> -#include <tqfile.h> -#include <tqsocket.h> -#include <tqdatetime.h> -#include <tqbitarray.h> -#include <tqregexp.h> - -#include <stdlib.h> -#ifdef HAVE_PTY_H -#include <pty.h> -#endif -#ifdef HAVE_TERMIOS_H -#include <termios.h> -#endif -#include <math.h> -#include <unistd.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <sys/types.h> -#ifdef HAVE_STROPTS -#include <stropts.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_LIBUTIL_H -#include <libutil.h> -#endif -#ifdef HAVE_UTIL_H -#include <util.h> -#endif - -#include <kdebug.h> -#include <kmessagebox.h> -#include <kinstance.h> -#include <kglobal.h> -#include <kstandarddirs.h> -#include <klocale.h> -#include <kremoteencoding.h> -#include <kurl.h> -#include <ksock.h> -#include <stdarg.h> -#include <time.h> -#include <sys/stat.h> -#include <kmimetype.h> -#include <kmimemagic.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <errno.h> -#include <sys/resource.h> - -#include "fish.h" -#include "fishcode.h" - -#ifndef NDEBUG -#define myDebug(x) kdDebug(7127) << __LINE__ << ": " x -#define connected() do{myDebug( << "_______ emitting connected()" << endl); connected();}while(0) -#define dataReq() do{myDebug( << "_______ emitting dataReq()" << endl); dataReq();}while(0) -#define needSubURLData() do{myDebug( << "_______ emitting needSubURLData()" << endl); needSubURLData();}while(0) -#define slaveStatus(x,y) do{myDebug( << "_______ emitting slaveStatus(" << x << ", " << y << ")" << endl); slaveStatus(x,y);}while(0) -#define statEntry(x) do{myDebug( << "_______ emitting statEntry("<<x.size()<<")" << endl); statEntry(x);}while(0) -#define listEntries(x) do{myDebug( << "_______ emitting listEntries(...)" << endl); listEntries(x);}while(0) -#define canResume(x) do{myDebug( << "_______ emitting canResume("<<(int)x<<")" << endl); canResume(x);}while(0) -#define totalSize(x) do{myDebug( << "_______ emitting totalSize("<<(int)x<<")" << endl); totalSize(x);}while(0) -#define processedSize(x) do{myDebug( << "_______ emitting processedSize("<<x<<")" << endl); processedSize(x);}while(0) -#define speed(x) do{myDebug( << "_______ emitting speed("<<(int)x<<")" << endl); speed(x);}while(0) -#define redirection(x) do{myDebug( << "_______ emitting redirection("<<x<<")" << endl); redirection(x);}while(0) -#define errorPage() do{myDebug( << "_______ emitting errorPage()" << endl); errorPage();}while(0) -#define sendmimeType(x) do{myDebug( << "_______ emitting mimeType("<<x<<")" << endl); mimeType(x);}while(0) -#define warning(x) do{myDebug( << "_______ emitting warning("<<x<<")" << endl); warning(x);}while(0) -#define infoMessage(x) do{myDebug( << "_______ emitting infoMessage("<<x<<")" << endl); infoMessage(x);}while(0) -#else -#define myDebug(x) -#define sendmimeType(x) mimeType(x) -#endif - -static char *sshPath = NULL; -static char *suPath = NULL; -// disabled: currently not needed. Didn't work reliably. -// static int isOpenSSH = 0; - -static int isNXFish = 0; - -#define E(x) ((const char*)remoteEncoding()->encode(x).data()) - -using namespace TDEIO; -extern "C" { - -static void ripper(int) -{ - while (waitpid(-1,0,WNOHANG) > 0) { - // do nothing, go on - } -} - -int KDE_EXPORT kdemain( int argc, char **argv ) -{ - KLocale::setMainCatalogue("kio_fish"); - TDEInstance instance("fish"); - - myDebug( << "*** Starting fish " << endl); - if (argc != 4) { - myDebug( << "Usage: fish protocol domain-socket1 domain-socket2" << endl); - exit(-1); - } - - setenv("TZ", "UTC", true); - - struct sigaction act; - memset(&act,0,sizeof(act)); - act.sa_handler = ripper; - act.sa_flags = 0 -#ifdef SA_NOCLDSTOP - | SA_NOCLDSTOP -#endif -#ifdef SA_RESTART - | SA_RESTART -#endif - ; - sigaction(SIGCHLD,&act,NULL); - - if (qstrcmp(argv[1],"nxfish")==0) { - // Set NXFish - Mode - isNXFish=1; - } - - fishProtocol slave(argv[2], argv[3]); - slave.dispatchLoop(); - - myDebug( << "*** fish Done" << endl); - return 0; -} - -} - -const struct fishProtocol::fish_info fishProtocol::fishInfo[] = { - { ("FISH"), 0, - ("echo; /bin/sh -c start_fish_server > /dev/null 2>/dev/null; perl .fishsrv.pl " CHECKSUM " 2>/dev/null; perl -e '$|=1; print \"### 100 transfer fish server\\n\"; while(<STDIN>) { last if /^__END__/; $code.=$_; } exit(eval($code));' 2>/dev/null;"), - 1 }, - { ("VER 0.0.3 copy append lscount lslinks lsmime exec stat"), 0, - ("echo 'VER 0.0.3 copy append lscount lslinks lsmime exec stat'"), - 1 }, - { ("PWD"), 0, - ("pwd"), - 1 }, - { ("LIST"), 1, - ("echo `ls -Lla %1 2> /dev/null | grep '^[-dsplcb]' | wc -l`; ls -Lla %1 2>/dev/null | grep '^[-dspl]' | ( while read -r p x u g s m d y n; do file -b -i $n 2>/dev/null | sed -e '\\,^[^/]*$,d;s/^/M/;s,/.*[ \t],/,'; FILE=%1; if [ -e %1\"/$n\" ]; then FILE=%1\"/$n\"; fi; if [ -L \"$FILE\" ]; then echo \":$n\"; ls -lad \"$FILE\" | sed -e 's/.* -> /L/'; else echo \":$n\" | sed -e 's/ -> /\\\nL/'; fi; echo \"P$p $u.$g\nS$s\nd$m $d $y\n\"; done; );" - "ls -Lla %1 2>/dev/null | grep '^[cb]' | ( while read -r p x u g a i m d y n; do echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"; done; )"), - 0 }, - { ("STAT"), 1, - ("echo `ls -dLla %1 2> /dev/null | grep '^[-dsplcb]' | wc -l`; ls -dLla %1 2>/dev/null | grep '^[-dspl]' | ( while read -r p x u g s m d y n; do file -b -i $n 2>/dev/null | sed -e '\\,^[^/]*$,d;s/^/M/;s,/.*[ \t],/,'; FILE=%1; if [ -e %1\"/$n\" ]; then FILE=%1\"/$n\"; fi; if [ -L \"$FILE\" ]; then echo \":$n\"; ls -lad \"$FILE\" | sed -e 's/.* -> /L/'; else echo \":$n\" | sed -e 's/ -> /\\\nL/'; fi; echo \"P$p $u.$g\nS$s\nd$m $d $y\n\"; done; );" - "ls -dLla %1 2>/dev/null | grep '^[cb]' | ( while read -r p x u g a i m d y n; do echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"; done; )"), - 0 }, - { ("RETR"), 1, - ("ls -l %1 2>&1 | ( read -r a b c d x e; echo $x ) 2>&1; echo '### 001'; cat %1"), - 1 }, - { ("STOR"), 2, - ("> %2; echo '### 001'; ( [ \"`expr %1 / 4096`\" -gt 0 ] && dd bs=4096 count=`expr %1 / 4096` 2>/dev/null;" - "[ \"`expr %1 % 4096`\" -gt 0 ] && dd bs=`expr %1 % 4096` count=1 2>/dev/null; ) | ( cat > %2 || echo Error $?; cat > /dev/null )"), - 0 }, - { ("CWD"), 1, - ("cd %1"), - 0 }, - { ("CHMOD"), 2, - ("chmod %1 %2"), - 0 }, - { ("DELE"), 1, - ("rm -f %1"), - 0 }, - { ("MKD"), 1, - ("mkdir %1"), - 0 }, - { ("RMD"), 1, - ("rmdir %1"), - 0 }, - { ("RENAME"), 2, - ("mv -f %1 %2"), - 0 }, - { ("LINK"), 2, - ("ln -f %1 %2"), - 0 }, - { ("SYMLINK"), 2, - ("ln -sf %1 %2"), - 0 }, - { ("CHOWN"), 2, - ("chown %1 %2"), - 0 }, - { ("CHGRP"), 2, - ("chgrp %1 %2"), - 0 }, - { ("READ"), 3, - ("echo '### 100';cat %3 /dev/zero | ( [ \"`expr %1 / 4096`\" -gt 0 ] && dd bs=4096 count=`expr %1 / 4096` >/dev/null;" - "[ \"`expr %1 % 4096`\" -gt 0 ] && dd bs=`expr %1 % 4096` count=1 >/dev/null;" - "dd bs=%2 count=1; ) 2>/dev/null;"), - 0 }, - // Yes, this is "ibs=1", since dd "count" is input blocks. - // On network connections, read() may not fill the buffer - // completely (no more data immediately available), but dd - // does ignore that fact by design. Sorry, writes are slow. - // OTOH, WRITE is not used by the current ioslave methods, - // we use APPEND. - { ("WRITE"), 3, - (">> %3; echo '### 001'; ( [ %2 -gt 0 ] && dd ibs=1 obs=%2 count=%2 2>/dev/null ) | " - "( dd ibs=32768 obs=%1 seek=1 of=%3 2>/dev/null || echo Error $?; cat >/dev/null; )"), - 0 }, - { ("COPY"), 2, - ("if [ -L %1 ]; then if cp -pdf %1 %2 2>/dev/null; then :; else LINK=\"`readlink %1`\"; ln -sf $LINK %2; fi; else cp -pf %1 %2; fi"), - 0 }, - { ("APPEND"), 2, - (">> %2; echo '### 001'; ( [ %1 -gt 0 ] && dd ibs=1 obs=%1 count=%1 2> /dev/null; ) | ( cat >> %2 || echo Error $?; cat >/dev/null; )"), - 0 }, - { ("EXEC"), 2, - ("UMASK=`umask`; umask 077; touch %2; umask $UMASK; eval %1 < /dev/null > %2 2>&1; echo \"###RESULT: $?\" >> %2"), - 0 } -}; - -fishProtocol::fishProtocol(const TQCString &pool_socket, const TQCString &app_socket) - : SlaveBase("fish", pool_socket, app_socket), mimeBuffer(1024), - mimeTypeSent(false) -{ - myDebug( << "fishProtocol::fishProtocol()" << endl); - if (sshPath == NULL) { - // disabled: currently not needed. Didn't work reliably. - // isOpenSSH = !system("ssh -V 2>&1 | grep OpenSSH > /dev/null"); - if (isNXFish) - sshPath = strdup(TQFile::encodeName(KStandardDirs::findExe("nxfish"))); - else - sshPath = strdup(TQFile::encodeName(KStandardDirs::findExe("ssh"))); - } - if (suPath == NULL) { - suPath = strdup(TQFile::encodeName(KStandardDirs::findExe("su"))); - } - childPid = 0; - connectionPort = 0; - isLoggedIn = false; - writeReady = true; - isRunning = false; - firstLogin = true; - errorCount = 0; - rawRead = 0; - rawWrite = -1; - recvLen = -1; - sendLen = -1; - setMultipleAuthCaching( true ); - connectionAuth.keepPassword = true; - connectionAuth.url.setProtocol("fish"); - outBufPos = -1; - outBuf = NULL; - outBufLen = 0; - typeAtom.m_uds = UDS_FILE_TYPE; - typeAtom.m_long = 0; - mimeAtom.m_uds = UDS_MIME_TYPE; - mimeAtom.m_long = 0; - mimeAtom.m_str = TQString::null; - - hasAppend = false; - - isStat = false; // FIXME: just a workaround for konq deficiencies - redirectUser = ""; // FIXME: just a workaround for konq deficiencies - redirectPass = ""; // FIXME: just a workaround for konq deficiencies - fishCodeLen = strlen(fishCode); -} -/* ---------------------------------------------------------------------------------- */ - - -fishProtocol::~fishProtocol() -{ - myDebug( << "fishProtocol::~fishProtocol()" << endl); - shutdownConnection(true); -} - -/* --------------------------------------------------------------------------- */ - -/** -Connects to a server and logs us in via SSH. Then starts FISH protocol. -*/ -void fishProtocol::openConnection() { - if (childPid) return; - - if (connectionHost.isEmpty() && !isNXFish) - { - error( TDEIO::ERR_UNKNOWN_HOST, TQString::null ); - return; - } - - infoMessage(i18n("Connecting...")); - - myDebug( << "connecting to: " << connectionUser << "@" << connectionHost << ":" << connectionPort << endl); - sendCommand(FISH_FISH); - sendCommand(FISH_VER); - if (connectionStart()) { - error(ERR_COULD_NOT_CONNECT,connectionHost); - shutdownConnection(); - return; - }; - myDebug( << "subprocess is running" << endl); -} - -static int open_pty_pair(int fd[2]) -{ -#if defined(HAVE_TERMIOS_H) && defined(HAVE_GRANTPT) && !defined(HAVE_OPENPTY) -/** with kind regards to The GNU C Library -Reference Manual for Version 2.2.x of the GNU C Library */ - int master, slave; - char *name; - struct ::termios ti; - memset(&ti,0,sizeof(ti)); - - ti.c_cflag = CLOCAL|CREAD|CS8; - ti.c_cc[VMIN] = 1; - -#ifdef HAVE_GETPT - master = getpt(); -#else - master = open("/dev/ptmx", O_RDWR); -#endif - if (master < 0) return 0; - - if (grantpt(master) < 0 || unlockpt(master) < 0) goto close_master; - - name = ptsname(master); - if (name == NULL) goto close_master; - - slave = open(name, O_RDWR); - if (slave == -1) goto close_master; - -#if (defined(HAVE_ISASTREAM) || defined(isastream)) && defined(I_PUSH) - if (isastream(slave) && - (ioctl(slave, I_PUSH, "ptem") < 0 || - ioctl(slave, I_PUSH, "ldterm") < 0)) - goto close_slave; -#endif - - tcsetattr(slave, TCSANOW, &ti); - fd[0] = master; - fd[1] = slave; - return 0; - -#if (defined(HAVE_ISASTREAM) || defined(isastream)) && defined(I_PUSH) -close_slave: -#endif - close(slave); - -close_master: - close(master); - return -1; -#else -#ifdef HAVE_OPENPTY - struct ::termios ti; - memset(&ti,0,sizeof(ti)); - - ti.c_cflag = CLOCAL|CREAD|CS8; - ti.c_cc[VMIN] = 1; - - return openpty(fd,fd+1,NULL,&ti,NULL); -#else -#ifdef __GNUC__ -#warning "No tty support available. Password dialog won't work." -#endif - return socketpair(PF_UNIX,SOCK_STREAM,0,fd); -#endif -#endif -} -/** -creates the subprocess -*/ -bool fishProtocol::connectionStart() { - int fd[2]; - int rc, flags; - thisFn = TQString::null; - - rc = open_pty_pair(fd); - if (rc == -1) { - myDebug( << "socketpair failed, error: " << strerror(errno) << endl); - return true; - } - - if (!requestNetwork()) return true; - myDebug( << "Exec: " << (local ? suPath : sshPath) << " Port: " << connectionPort << " User: " << connectionUser << endl); - childPid = fork(); - if (childPid == -1) { - myDebug( << "fork failed, error: " << strerror(errno) << endl); - close(fd[0]); - close(fd[1]); - childPid = 0; - dropNetwork(); - return true; - } - if (childPid == 0) { - // taken from konsole, see TEPty.C for details - // note: if we're running on socket pairs, - // this will fail, but thats what we expect - - for (int sig = 1; sig < NSIG; sig++) signal(sig,SIG_DFL); - - struct rlimit rlp; - getrlimit(RLIMIT_NOFILE, &rlp); - for (int i = 0; i < (int)rlp.rlim_cur; i++) - if (i != fd[1]) close(i); - - dup2(fd[1],0); - dup2(fd[1],1); - dup2(fd[1],2); - if (fd[1] > 2) close(fd[1]); - - setsid(); - -#if defined(TIOCSCTTY) - ioctl(0, TIOCSCTTY, 0); -#endif - - int pgrp = getpid(); -#if defined( _AIX) || defined( __hpux) - tcsetpgrp(0, pgrp); -#else - ioctl(0, TIOCSPGRP, (char *)&pgrp); -#endif - - const char *dev = ttyname(0); - setpgid(0,0); - if (dev) close(open(dev, O_WRONLY, 0)); - setpgid(0,0); - - if (local) { - execl(suPath, "su", "-", connectionUser.latin1(), "-c", "cd ~;echo FISH:;exec /bin/sh -c \"if env true 2>/dev/null; then env PS1= PS2= TZ=UTC LANG=C LC_ALL=C LOCALE=C /bin/sh; else PS1= PS2= TZ=UTC LANG=C LC_ALL=C LOCALE=C /bin/sh; fi\"", (void *)0); - } else { - #define common_args "-l", connectionUser.latin1(), "-x", "-e", "none", \ - "-q", connectionHost.latin1(), \ - "echo FISH:;exec /bin/sh -c \"if env true 2>/dev/null; then env PS1= PS2= TZ=UTC LANG=C LC_ALL=C LOCALE=C /bin/sh; else PS1= PS2= TZ=UTC LANG=C LC_ALL=C LOCALE=C /bin/sh; fi\"", (void *)0 - // disabled: leave compression up to the client. - // (isOpenSSH?"-C":"+C"), - - if (connectionPort) - execl(sshPath, "ssh", "-p", TQString::number(connectionPort).latin1(), common_args); - else - execl(sshPath, "ssh", common_args); - #undef common_args - } - myDebug( << "could not exec! " << strerror(errno) << endl); - ::exit(-1); - } - close(fd[1]); - rc = fcntl(fd[0],F_GETFL,&flags); - rc = fcntl(fd[0],F_SETFL,flags|O_NONBLOCK); - childFd = fd[0]; - - fd_set rfds, wfds; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - char buf[32768]; - int offset = 0; - while (!isLoggedIn) { - FD_SET(childFd,&rfds); - FD_ZERO(&wfds); - if (outBufPos >= 0) FD_SET(childFd,&wfds); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 1000; - rc = select(childFd+1, &rfds, &wfds, NULL, &timeout); - if (rc < 0) { - if (errno == EINTR) - continue; - myDebug( << "select failed, rc: " << rc << ", error: " << strerror(errno) << endl); - return true; - } - if (FD_ISSET(childFd,&wfds) && outBufPos >= 0) { - if (outBuf) rc = write(childFd,outBuf+outBufPos,outBufLen-outBufPos); - else rc = 0; - if (rc >= 0) outBufPos += rc; - else { - if (errno == EINTR) - continue; - myDebug( << "write failed, rc: " << rc << ", error: " << strerror(errno) << endl); - outBufPos = -1; - //return true; - } - if (outBufPos >= outBufLen) { - outBufPos = -1; - outBuf = NULL; - outBufLen = 0; - } - } - if (FD_ISSET(childFd,&rfds)) { - rc = read(childFd,buf+offset,32768-offset); - if (rc > 0) { - int noff = establishConnection(buf,rc+offset); - if (noff < 0) return false; - if (noff > 0) memmove(buf,buf+offset+rc-noff,noff); - offset = noff; - } else { - if (errno == EINTR) - continue; - myDebug( << "read failed, rc: " << rc << ", error: " << strerror(errno) << endl); - return true; - } - } - } - return false; -} - -/** -writes one chunk of data to stdin of child process -*/ -void fishProtocol::writeChild(const char *buf, TDEIO::fileoffset_t len) { - if (outBufPos >= 0 && outBuf) { -#if 0 - TQString debug; - debug.setLatin1(outBuf,outBufLen); - if (len > 0) myDebug( << "write request while old one is pending, throwing away input (" << outBufLen << "," << outBufPos << "," << debug.left(10) << "...)" << endl); -#endif - return; - } - outBuf = buf; - outBufPos = 0; - outBufLen = len; -} - -/** -manages initial communication setup including password queries -*/ -int fishProtocol::establishConnection(char *buffer, TDEIO::fileoffset_t len) { - TQString buf; - buf.setLatin1(buffer,len); - int pos; - // Strip trailing whitespace - while (buf.length() && (buf[buf.length()-1] == ' ')) - buf.truncate(buf.length()-1); - - myDebug( << "establishing: got " << buf << endl); - while (childPid && ((pos = buf.find('\n')) >= 0 || - buf.endsWith(":") || buf.endsWith("?"))) { - pos++; - TQString str = buf.left(pos); - buf = buf.mid(pos); - if (str == "\n") - continue; - if (str == "FISH:\n") { - thisFn = TQString::null; - infoMessage(i18n("Initiating protocol...")); - if (!connectionAuth.password.isEmpty()) { - connectionAuth.password = connectionAuth.password.left(connectionAuth.password.length()-1); - cacheAuthentication(connectionAuth); - } - isLoggedIn = true; - return 0; - } else if (!str.isEmpty()) { - thisFn += str; - } else if (buf.endsWith(":")) { - if (!redirectUser.isEmpty() && connectionUser != redirectUser) { - KURL dest = url; - dest.setUser(redirectUser); - dest.setPass(redirectPass); - redirection(dest); - commandList.clear(); - commandCodes.clear(); - finished(); - redirectUser = ""; - redirectPass = ""; - return -1; - } else if (!connectionPassword.isEmpty()) { - myDebug( << "sending cpass" << endl); - connectionAuth.password = connectionPassword+"\n"; - connectionPassword = TQString::null; - // su does not like receiving a password directly after sending - // the password prompt so we wait a while. - if (local) - sleep(1); - writeChild(connectionAuth.password.latin1(),connectionAuth.password.length()); - } else { - myDebug( << "sending mpass" << endl); - connectionAuth.prompt = thisFn+buf; - if (local) - connectionAuth.caption = i18n("Local Login") + " - " + url.user() + "@" + url.host(); - else - connectionAuth.caption = i18n("SSH Authorization") + " - " + url.user() + "@" + url.host(); - if ((!firstLogin || !checkCachedAuthentication(connectionAuth))) { - connectionAuth.password = TQString::null; // don't prefill - if ( !openPassDlg(connectionAuth)) { - error(ERR_USER_CANCELED,connectionHost); - shutdownConnection(); - return -1; - } - } - firstLogin = false; - connectionAuth.password += "\n"; - if (connectionAuth.username != connectionUser) { - KURL dest = url; - dest.setUser(connectionAuth.username); - dest.setPass(connectionAuth.password); - redirection(dest); - if (isStat) { // FIXME: just a workaround for konq deficiencies - redirectUser = connectionAuth.username; - redirectPass = connectionAuth.password; - } - commandList.clear(); - commandCodes.clear(); - finished(); - return -1; - } - myDebug( << "sending pass" << endl); - if (local) - sleep(1); - writeChild(connectionAuth.password.latin1(),connectionAuth.password.length()); - } - thisFn = TQString::null; - return 0; - } else if (buf.endsWith("?")) { - int rc = messageBox(QuestionYesNo,thisFn+buf); - if (rc == KMessageBox::Yes) { - writeChild("yes\n",4); - } else { - writeChild("no\n",3); - } - thisFn = TQString::null; - return 0; - } else { - myDebug( << "unmatched case in initial handling! shouldn't happen!" << endl); - } - } - return buf.length(); -} -/** -sets connection information for subsequent commands -*/ -void fishProtocol::setHost(const TQString & host, int port, const TQString & u, const TQString & pass){ - TQString user(u); - - if (isNXFish) - local = 0; - else - local = (host == "localhost" && port == 0); - - if (port <= 0) port = 0; - if (user.isEmpty()) user = getenv("LOGNAME"); - - if (host == connectionHost && port == connectionPort && user == connectionUser) - return; - myDebug( << "setHost " << u << "@" << host << endl); - - if (childPid) shutdownConnection(); - - connectionHost = host; - connectionAuth.url.setHost(host); - - connectionUser = user; - connectionAuth.username = user; - connectionAuth.url.setUser(user); - - connectionPort = port; - connectionPassword = pass; - firstLogin = true; -} - -/** -Forced close of the connection - -This function gets called from the application side of the universe, -it shouldn't send any response. - */ -void fishProtocol::closeConnection(){ - myDebug( << "closeConnection()" << endl); - shutdownConnection(true); -} - -/** -Closes the connection - */ -void fishProtocol::shutdownConnection(bool forced){ - if (childPid) { - kill(childPid,SIGTERM); // We may not have permission... - childPid = 0; - close(childFd); // ...in which case this should do the trick - childFd = -1; - if (!forced) - { - dropNetwork(); - infoMessage(i18n("Disconnected.")); - } - } - outBufPos = -1; - outBuf = NULL; - outBufLen = 0; - qlist.clear(); - commandList.clear(); - commandCodes.clear(); - isLoggedIn = false; - writeReady = true; - isRunning = false; - rawRead = 0; - rawWrite = -1; - recvLen = -1; - sendLen = -1; -} -/** -builds each FISH request and sets the error counter -*/ -bool fishProtocol::sendCommand(fish_command_type cmd, ...) { - const fish_info &info = fishInfo[cmd]; - myDebug( << "queueing: cmd="<< cmd << "['" << info.command << "'](" << info.params <<"), alt=['" << info.alt << "'], lines=" << info.lines << endl); - - va_list list; - va_start(list, cmd); - TQString realCmd = info.command; - TQString realAlt = info.alt; - static TQRegExp rx("[][\\\\\n $`#!()*?{}~&<>;'\"%^@|\t]"); - for (int i = 0; i < info.params; i++) { - TQString arg(va_arg(list, const char *)); - int pos = -2; - while ((pos = rx.search(arg,pos+2)) >= 0) { - arg.replace(pos,0,TQString("\\")); - } - //myDebug( << "arg " << i << ": " << arg << endl); - realCmd.append(" ").append(arg); - realAlt.replace(TQRegExp("%"+TQString::number(i+1)),arg); - } - TQString s("#"); - s.append(realCmd).append("\n ").append(realAlt).append(" 2>&1;echo '### 000'\n"); - if (realCmd == "FISH") - s.prepend(" "); - commandList.append(s); - commandCodes.append(cmd); - return true; -} - -/** -checks response string for result code, converting 000 and 001 appropriately -*/ -int fishProtocol::handleResponse(const TQString &str){ - myDebug( << "handling: " << str << endl); - if (str.startsWith("### ")) { - bool isOk = false; - int result = str.mid(4,3).toInt(&isOk); - if (!isOk) result = 500; - if (result == 0) result = (errorCount != 0?500:200); - if (result == 1) result = (errorCount != 0?500:100); - myDebug( << "result: " << result << ", errorCount: " << errorCount << endl); - return result; - } else { - errorCount++; - return 0; - } -} - -int fishProtocol::makeTimeFromLs(const TQString &monthStr, const TQString &dayStr, const TQString &timeyearStr) -{ - TQDateTime dt(TQDate::currentDate(Qt::UTC)); - int year = dt.date().year(); - int month = dt.date().month(); - int currentMonth = month; - int day = dayStr.toInt(); - - static const char * const monthNames[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - - for (int i=0; i < 12; i++) if (monthStr.startsWith(monthNames[i])) { - month = i+1; - break; - } - - int pos = timeyearStr.find(':'); - if (timeyearStr.length() == 4 && pos == -1) { - year = timeyearStr.toInt(); - } else if (pos == -1) { - return 0; - } else { - if (month > currentMonth + 1) year--; - dt.time().setHMS(timeyearStr.left(pos).toInt(),timeyearStr.mid(pos+1).toInt(),0); - } - dt.date().setYMD(year,month,day); - - return dt.toTime_t(); -} - -/** -parses response from server and acts accordingly -*/ -void fishProtocol::manageConnection(const TQString &l) { - TQString line(l); - int rc = handleResponse(line); - UDSAtom atom; - TQDateTime dt; - TDEIO::filesize_t fsize; - int pos, pos2, pos3; - bool isOk = false; - if (!rc) { - switch (fishCommand) { - case FISH_VER: - if (line.startsWith("VER 0.0.3")) { - line.append(" "); - hasAppend = line.contains(" append "); - } else { - error(ERR_UNSUPPORTED_PROTOCOL,line); - shutdownConnection(); - } - break; - case FISH_PWD: - url.setPath(line); - redirection(url); - break; - case FISH_LIST: - myDebug( << "listReason: " << listReason << endl); - /* Fall through */ - case FISH_STAT: - if (line.length() > 0) { - switch (line[0].cell()) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - fsize = line.toULongLong(&isOk); - if (fsize > 0 && isOk) errorCount--; - if ((fishCommand == FISH_LIST) && (listReason == LIST)) - totalSize(fsize); - break; - - case 'P': - errorCount--; - if (line[1] == 'd') { - mimeAtom.m_str = "inode/directory"; - typeAtom.m_long = S_IFDIR; - } else { - if (line[1] == '-') { - typeAtom.m_long = S_IFREG; - } else if (line[1] == 'l') { - typeAtom.m_long = S_IFLNK; - } else if (line[1] == 'c') { - typeAtom.m_long = S_IFCHR; - } else if (line[1] == 'b') { - typeAtom.m_long = S_IFBLK; - } else if (line[1] == 's') { - typeAtom.m_long = S_IFSOCK; - } else if (line[1] == 'p') { - typeAtom.m_long = S_IFIFO; - } else { - myDebug( << "unknown file type: " << line[1].cell() << endl); - errorCount++; - break; - } - } - //myDebug( << "file type: " << atom.m_long << endl); - //udsEntry.append(atom); - - atom.m_uds = UDS_ACCESS; - atom.m_long = 0; - if (line[2] == 'r') atom.m_long |= S_IRUSR; - if (line[3] == 'w') atom.m_long |= S_IWUSR; - if (line[4] == 'x' || line[4] == 's') atom.m_long |= S_IXUSR; - if (line[4] == 'S' || line[4] == 's') atom.m_long |= S_ISUID; - if (line[5] == 'r') atom.m_long |= S_IRGRP; - if (line[6] == 'w') atom.m_long |= S_IWGRP; - if (line[7] == 'x' || line[7] == 's') atom.m_long |= S_IXGRP; - if (line[7] == 'S' || line[7] == 's') atom.m_long |= S_ISGID; - if (line[8] == 'r') atom.m_long |= S_IROTH; - if (line[9] == 'w') atom.m_long |= S_IWOTH; - if (line[10] == 'x' || line[10] == 't') atom.m_long |= S_IXOTH; - if (line[10] == 'T' || line[10] == 't') atom.m_long |= S_ISVTX; - udsEntry.append(atom); - - atom.m_uds = UDS_USER; - atom.m_long = 0; - pos = line.find('.',12); - if (pos < 0) { - errorCount++; - break; - } - atom.m_str = line.mid(12,pos-12); - udsEntry.append(atom); - - atom.m_uds = UDS_GROUP; - atom.m_long = 0; - atom.m_str = line.mid(pos+1); - udsEntry.append(atom); - break; - - case 'd': - atom.m_uds = UDS_MODIFICATION_TIME; - pos = line.find(' '); - pos2 = line.find(' ',pos+1); - if (pos < 0 || pos2 < 0) break; - errorCount--; - atom.m_long = makeTimeFromLs(line.mid(1,pos-1), line.mid(pos+1,pos2-pos), line.mid(pos2+1)); - udsEntry.append(atom); - break; - - case 'D': - atom.m_uds = UDS_MODIFICATION_TIME; - pos = line.find(' '); - pos2 = line.find(' ',pos+1); - pos3 = line.find(' ',pos2+1); - if (pos < 0 || pos2 < 0 || pos3 < 0) break; - dt.setDate(TQDate(line.mid(1,pos-1).toInt(),line.mid(pos+1,pos2-pos-1).toInt(),line.mid(pos2+1,pos3-pos2-1).toInt())); - pos = pos3; - pos2 = line.find(' ',pos+1); - pos3 = line.find(' ',pos2+1); - if (pos < 0 || pos2 < 0 || pos3 < 0) break; - dt.setTime(TQTime(line.mid(pos+1,pos2-pos-1).toInt(),line.mid(pos2+1,pos3-pos2-1).toInt(),line.mid(pos3+1).toInt())); - errorCount--; - atom.m_long = dt.toTime_t(); - udsEntry.append(atom); - break; - - case 'S': - atom.m_uds = UDS_SIZE; - atom.m_long = line.mid(1).toULongLong(&isOk); - if (!isOk) break; - errorCount--; - udsEntry.append(atom); - break; - - case 'E': - errorCount--; - break; - - case ':': - atom.m_uds = UDS_NAME; - atom.m_long = 0; - pos = line.findRev('/'); - atom.m_str = thisFn = line.mid(pos < 0?1:pos+1); - if (fishCommand == FISH_LIST) - udsEntry.append(atom); - // By default, the mimetype comes from the extension - // We'll use the file(1) result only as fallback [like the rest of KDE does] - { - KURL kurl("fish://host/"); - kurl.setFileName(thisFn); // properly encode special chars - KMimeType::Ptr mime = KMimeType::findByURL(kurl); - if ( mime->name() != KMimeType::defaultMimeType() ) - mimeAtom.m_str = mime->name(); - } - errorCount--; - break; - - case 'M': { - TQString type = line.mid(1); - - // First thing's first. If remote says this is a directory, throw out any - // name-based file type guesses. - if (type == "inode/directory" && mimeAtom.m_str != type) { - mimeAtom.m_str = type; - typeAtom.m_long = S_IFDIR; - } - // This is getting ugly. file(1) makes some uneducated - // guesses, so we must try to ignore them (#51274) - else if (mimeAtom.m_str.isEmpty() && line.right(8) != "/unknown" && - (thisFn.find('.') < 0 || (line.left(8) != "Mtext/x-" - && line != "Mtext/plain"))) { - mimeAtom.m_str = type; - } - errorCount--; - break; - } - - case 'L': - atom.m_uds = UDS_LINK_DEST; - atom.m_long = 0; - atom.m_str = line.mid(1); - udsEntry.append(atom); - if (!typeAtom.m_long) typeAtom.m_long = S_IFLNK; - errorCount--; - break; - } - } else { - if (!mimeAtom.m_str.isNull()) - udsEntry.append(mimeAtom); - mimeAtom.m_str = TQString::null; - - udsEntry.append(typeAtom); - typeAtom.m_long = 0; - - if (fishCommand == FISH_STAT) - udsStatEntry = udsEntry; - else if (listReason == LIST) { - listEntry(udsEntry, false); //1 - } else if (listReason == CHECK) checkExist = true; //0 - errorCount--; - udsEntry.clear(); - } - break; - - case FISH_RETR: - if (line.length() == 0) { - error(ERR_IS_DIRECTORY,url.prettyURL()); - recvLen = 0; - break; - } - recvLen = line.toLongLong(&isOk); - if (!isOk) { - error(ERR_COULD_NOT_READ,url.prettyURL()); - shutdownConnection(); - break; - } - break; - default : break; - } - - } else if (rc == 100) { - switch (fishCommand) { - case FISH_FISH: - writeChild(fishCode, fishCodeLen); - break; - case FISH_READ: - recvLen = 1024; - /* fall through */ - case FISH_RETR: - myDebug( << "reading " << recvLen << endl); - if (recvLen == -1) { - error(ERR_COULD_NOT_READ,url.prettyURL()); - shutdownConnection(); - } else { - rawRead = recvLen; - dataRead = 0; - mimeTypeSent = false; - if (recvLen == 0) - { - mimeType("application/x-zerosize"); - mimeTypeSent = true; - } - } - break; - case FISH_STOR: - case FISH_WRITE: - case FISH_APPEND: - rawWrite = sendLen; - //myDebug( << "sending " << sendLen << endl); - writeChild(NULL,0); - break; - default : break; - } - } else if (rc/100 != 2) { - switch (fishCommand) { - case FISH_STOR: - case FISH_WRITE: - case FISH_APPEND: - error(ERR_COULD_NOT_WRITE,url.prettyURL()); - shutdownConnection(); - break; - case FISH_RETR: - error(ERR_COULD_NOT_READ,url.prettyURL()); - shutdownConnection(); - break; - case FISH_READ: - if ( rc == 501 ) - { - mimeType("inode/directory"); - mimeTypeSent = true; - recvLen = 0; - finished(); - } - else - { - error(ERR_COULD_NOT_READ,url.prettyURL()); - shutdownConnection(); - } - break; - case FISH_FISH: - case FISH_VER: - error(ERR_SLAVE_DEFINED,line); - shutdownConnection(); - break; - case FISH_PWD: - case FISH_CWD: - error(ERR_CANNOT_ENTER_DIRECTORY,url.prettyURL()); - break; - case FISH_LIST: - myDebug( << "list error. reason: " << listReason << endl); - if (listReason == LIST) error(ERR_CANNOT_ENTER_DIRECTORY,url.prettyURL()); - else if (listReason == CHECK) { - checkExist = false; - finished(); - } - break; - case FISH_STAT: - error(ERR_DOES_NOT_EXIST,url.prettyURL()); - udsStatEntry.clear(); - break; - case FISH_CHMOD: - error(ERR_CANNOT_CHMOD,url.prettyURL()); - break; - case FISH_CHOWN: - case FISH_CHGRP: - error(ERR_ACCESS_DENIED,url.prettyURL()); - break; - case FISH_MKD: - if ( rc == 501 ) - error(ERR_DIR_ALREADY_EXIST,url.prettyURL()); - else - error(ERR_COULD_NOT_MKDIR,url.prettyURL()); - break; - case FISH_RMD: - error(ERR_COULD_NOT_RMDIR,url.prettyURL()); - break; - case FISH_DELE: - error(ERR_CANNOT_DELETE,url.prettyURL()); - break; - case FISH_RENAME: - error(ERR_CANNOT_RENAME,url.prettyURL()); - break; - case FISH_COPY: - case FISH_LINK: - case FISH_SYMLINK: - error(ERR_COULD_NOT_WRITE,url.prettyURL()); - break; - default : break; - } - } else { - if (fishCommand == FISH_STOR) fishCommand = (hasAppend?FISH_APPEND:FISH_WRITE); - if (fishCommand == FISH_FISH) { - connected(); - } else if (fishCommand == FISH_LIST) { - if (listReason == LIST) { - listEntry(UDSEntry(),true); - } else if (listReason == CHECK) { - if (!checkOverwrite && checkExist) - { - error(ERR_FILE_ALREADY_EXIST,url.prettyURL()); - return; // Don't call finished! - } - } - } else if (fishCommand == FISH_STAT) { - UDSAtom atom; - - atom.m_uds = TDEIO::UDS_NAME; - atom.m_str = url.fileName(); - udsStatEntry.append( atom ); - statEntry(udsStatEntry); - } else if (fishCommand == FISH_APPEND) { - dataReq(); - if (readData(rawData) > 0) sendCommand(FISH_APPEND,E(TQString::number(rawData.size())),E(url.path())); - else if (!checkExist && putPerm > -1) sendCommand(FISH_CHMOD,E(TQString::number(putPerm,8)),E(url.path())); - sendLen = rawData.size(); - } else if (fishCommand == FISH_WRITE) { - dataReq(); - if (readData(rawData) > 0) sendCommand(FISH_WRITE,E(TQString::number(putPos)),E(TQString::number(rawData.size())),E(url.path())); - else if (!checkExist && putPerm > -1) sendCommand(FISH_CHMOD,E(TQString::number(putPerm,8)),E(url.path())); - putPos += rawData.size(); - sendLen = rawData.size(); - } else if (fishCommand == FISH_RETR) { - data(TQByteArray()); - } - finished(); - } -} - -void fishProtocol::writeStdin(const TQString &line) -{ - qlist.append(line); - - if (writeReady) { - writeReady = false; - //myDebug( << "Writing: " << qlist.first().mid(0,qlist.first().find('\n')) << endl); - myDebug( << "Writing: " << qlist.first() << endl); - myDebug( << "---------" << endl); - writeChild((const char *)qlist.first().latin1(), qlist.first().length()); - } -} - -void fishProtocol::sent() -{ - if (rawWrite > 0) { - myDebug( << "writing raw: " << rawData.size() << "/" << rawWrite << endl); - writeChild(rawData.data(),(rawWrite > rawData.size()?rawData.size():rawWrite)); - rawWrite -= rawData.size(); - if (rawWrite > 0) { - dataReq(); - if (readData(rawData) <= 0) { - shutdownConnection(); - } - } - return; - } else if (rawWrite == 0) { - // workaround: some dd's insist in reading multiples of - // 8 bytes, swallowing up to seven bytes. Sending - // newlines is safe even when a sane dd is used - writeChild("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",15); - rawWrite = -1; - return; - } - if (qlist.count() > 0) qlist.remove(qlist.begin()); - if (qlist.count() == 0) { - writeReady = true; - } else { - //myDebug( << "Writing: " << qlist.first().mid(0,qlist.first().find('\n')) << endl); - myDebug( << "Writing: " << qlist.first() << endl); - myDebug( << "---------" << endl); - writeChild((const char *)qlist.first().latin1(),qlist.first().length()); - } -} - -int fishProtocol::received(const char *buffer, TDEIO::fileoffset_t buflen) -{ - int pos = 0; - do { - if (buflen <= 0) break; - - if (rawRead > 0) { - //myDebug( << "processedSize " << dataRead << ", len " << buflen << "/" << rawRead << endl); - int dataSize = (rawRead > buflen?buflen:rawRead); - if (!mimeTypeSent) - { - int mimeSize = TQMIN(dataSize, (int)mimeBuffer.size()-dataRead); - memcpy(mimeBuffer.data()+dataRead,buffer,mimeSize); - dataRead += mimeSize; - rawRead -= mimeSize; - buffer += mimeSize; - buflen -= mimeSize; - if (rawRead == 0) // End of data - mimeBuffer.resize(dataRead); - if (dataRead < (int)mimeBuffer.size()) - { - myDebug( << "wait for more" << endl); - break; - } - - // We need a KMimeType::findByNameAndContent(filename,data) - // For now we do: find by extension, and if not found (or extension not reliable) - // then find by content. - bool accurate = false; - KMimeType::Ptr mime = KMimeType::findByURL( url, 0, false, true, &accurate ); - if ( !mime || mime->name() == KMimeType::defaultMimeType() - || !accurate ) - { - KMimeType::Ptr p_mimeType = KMimeType::findByContent(mimeBuffer); - if ( p_mimeType && p_mimeType->name() != KMimeType::defaultMimeType() ) - mime = p_mimeType; - } - - sendmimeType(mime->name()); - - - mimeTypeSent = true; - if (fishCommand != FISH_READ) { - totalSize(dataRead + rawRead); - data(mimeBuffer); - processedSize(dataRead); - } - mimeBuffer.resize(1024); - pos = 0; - continue; // Process rest of buffer/buflen - } - - TQByteArray bdata; - bdata.duplicate(buffer,dataSize); - data(bdata); - - dataRead += dataSize; - rawRead -= dataSize; - processedSize(dataRead); - if (rawRead <= 0) { - buffer += dataSize; - buflen -= dataSize; - } else { - return 0; - } - } - - if (buflen <= 0) break; - - pos = 0; - // Find newline - while((pos < buflen) && (buffer[pos] != '\n')) - ++pos; - - if (pos < buflen) - { - TQString s = remoteEncoding()->decode(TQCString(buffer,pos+1)); - - buffer += pos+1; - buflen -= pos+1; - - manageConnection(s); - - pos = 0; - // Find next newline - while((pos < buflen) && (buffer[pos] != '\n')) - ++pos; - } - } while (childPid && buflen && (rawRead > 0 || pos < buflen)); - return buflen; -} -/** get a file */ -void fishProtocol::get(const KURL& u){ - myDebug( << "@@@@@@@@@ get " << u << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - recvLen = -1; - sendCommand(FISH_RETR,E(url.path())); - } - run(); -} - -/** put a file */ -void fishProtocol::put(const KURL& u, int permissions, bool overwrite, bool /*resume*/){ - myDebug( << "@@@@@@@@@ put " << u << " " << permissions << " " << overwrite << " " /* << resume */ << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - putPerm = permissions; - checkOverwrite = overwrite; - checkExist = false; - putPos = 0; - listReason = CHECK; - sendCommand(FISH_LIST,E(url.path())); - sendCommand(FISH_STOR,"0",E(url.path())); - } - run(); -} -/** executes next command in sequence or calls finished() if all is done */ -void fishProtocol::finished() { - if (commandList.count() > 0) { - fishCommand = (fish_command_type)commandCodes.first(); - errorCount = -fishInfo[fishCommand].lines; - rawRead = 0; - rawWrite = -1; - udsEntry.clear(); - udsStatEntry.clear(); - writeStdin(commandList.first()); - //if (fishCommand != FISH_APPEND && fishCommand != FISH_WRITE) infoMessage("Sending "+(commandList.first().mid(1,commandList.first().find("\n")-1))+"..."); - commandList.remove(commandList.begin()); - commandCodes.remove(commandCodes.begin()); - } else { - myDebug( << "_______ emitting finished()" << endl); - SlaveBase::finished(); - isRunning = false; - } -} -/** aborts command sequence and calls error() */ -void fishProtocol::error(int type, const TQString &detail) { - commandList.clear(); - commandCodes.clear(); - myDebug( << "ERROR: " << type << " - " << detail << endl); - SlaveBase::error(type,detail); - isRunning = false; -} -/** executes a chain of commands */ -void fishProtocol::run() { - if (!isRunning) { - int rc; - isRunning = true; - finished(); - fd_set rfds, wfds; - FD_ZERO(&rfds); - char buf[32768]; - int offset = 0; - while (isRunning) { - FD_SET(childFd,&rfds); - FD_ZERO(&wfds); - if (outBufPos >= 0) FD_SET(childFd,&wfds); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 1000; - rc = select(childFd+1, &rfds, &wfds, NULL, &timeout); - if (rc < 0) { - if (errno == EINTR) - continue; - myDebug( << "select failed, rc: " << rc << ", error: " << strerror(errno) << endl); - error(ERR_CONNECTION_BROKEN,connectionHost); - shutdownConnection(); - return; - } - if (FD_ISSET(childFd,&wfds) && outBufPos >= 0) { -#if 0 - TQString debug; - debug.setLatin1(outBuf+outBufPos,outBufLen-outBufPos); - myDebug( << "now writing " << (outBufLen-outBufPos) << " " << debug.left(40) << "..." << endl); -#endif - if (outBufLen-outBufPos > 0) rc = write(childFd,outBuf+outBufPos,outBufLen-outBufPos); - else rc = 0; - if (rc >= 0) outBufPos += rc; - else { - if (errno == EINTR) - continue; - myDebug( << "write failed, rc: " << rc << ", error: " << strerror(errno) << endl); - error(ERR_CONNECTION_BROKEN,connectionHost); - shutdownConnection(); - return; - } - if (outBufPos >= outBufLen) { - outBufPos = -1; - outBuf = NULL; - sent(); - } - } - else if (FD_ISSET(childFd,&rfds)) { - rc = read(childFd,buf+offset,32768-offset); - //myDebug( << "read " << rc << " bytes" << endl); - if (rc > 0) { - int noff = received(buf,rc+offset); - if (noff > 0) memmove(buf,buf+offset+rc-noff,noff); - //myDebug( << "left " << noff << " bytes: " << TQString::fromLatin1(buf,offset) << endl); - offset = noff; - } else { - if (errno == EINTR) - continue; - myDebug( << "read failed, rc: " << rc << ", error: " << strerror(errno) << endl); - error(ERR_CONNECTION_BROKEN,connectionHost); - shutdownConnection(); - return; - } - } - if (wasKilled()) - return; - } - } -} -/** stat a file */ -void fishProtocol::stat(const KURL& u){ - myDebug( << "@@@@@@@@@ stat " << u << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - isStat = true; // FIXME: just a workaround for konq deficiencies - openConnection(); - isStat = false; // FIXME: just a workaround for konq deficiencies - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - sendCommand(FISH_STAT,E(url.path(-1))); - } - run(); -} -/** find mimetype for a file */ -void fishProtocol::mimetype(const KURL& u){ - myDebug( << "@@@@@@@@@ mimetype " << u << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - recvLen = 1024; - sendCommand(FISH_READ,"0","1024",E(url.path())); - } - run(); -} -/** list a directory */ -void fishProtocol::listDir(const KURL& u){ - myDebug( << "@@@@@@@@@ listDir " << u << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - listReason = LIST; - sendCommand(FISH_LIST,E(url.path())); - } - run(); -} -/** create a directory */ -void fishProtocol::mkdir(const KURL& u, int permissions) { - myDebug( << "@@@@@@@@@ mkdir " << u << " " << permissions << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - sendCommand(FISH_MKD,E(url.path())); - if (permissions > -1) sendCommand(FISH_CHMOD,E(TQString::number(permissions,8)),E(url.path())); - } - run(); -} -/** rename a file */ -void fishProtocol::rename(const KURL& s, const KURL& d, bool overwrite) { - myDebug( << "@@@@@@@@@ rename " << s << " " << d << " " << overwrite << endl); - if (s.host() != d.host() || s.port() != d.port() || s.user() != d.user()) { - error(ERR_UNSUPPORTED_ACTION,s.prettyURL()); - return; - } - setHost(s.host(),s.port(),s.user(),s.pass()); - url = d; - openConnection(); - if (!isLoggedIn) return; - KURL src = s; - url.cleanPath(); - src.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - if (!overwrite) { - listReason = CHECK; - checkOverwrite = false; - sendCommand(FISH_LIST,E(url.path())); - } - sendCommand(FISH_RENAME,E(src.path()),E(url.path())); - } - run(); -} -/** create a symlink */ -void fishProtocol::symlink(const TQString& target, const KURL& u, bool overwrite) { - myDebug( << "@@@@@@@@@ symlink " << target << " " << u << " " << overwrite << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - if (!overwrite) { - listReason = CHECK; - checkOverwrite = false; - sendCommand(FISH_LIST,E(url.path())); - } - sendCommand(FISH_SYMLINK,E(target),E(url.path())); - } - run(); -} -/** change file permissions */ -void fishProtocol::chmod(const KURL& u, int permissions){ - myDebug( << "@@@@@@@@@ chmod " << u << " " << permissions << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - if (permissions > -1) sendCommand(FISH_CHMOD,E(TQString::number(permissions,8)),E(url.path())); - } - run(); -} -/** copies a file */ -void fishProtocol::copy(const KURL &s, const KURL &d, int permissions, bool overwrite) { - myDebug( << "@@@@@@@@@ copy " << s << " " << d << " " << permissions << " " << overwrite << endl); - if (s.host() != d.host() || s.port() != d.port() || s.user() != d.user()) { - error(ERR_UNSUPPORTED_ACTION,s.prettyURL()); - return; - } - //myDebug( << s << endl << d << endl); - setHost(s.host(),s.port(),s.user(),s.pass()); - url = d; - openConnection(); - if (!isLoggedIn) return; - KURL src = s; - url.cleanPath(); - src.cleanPath(); - if (!src.hasPath()) { - sendCommand(FISH_PWD); - } else { - if (!overwrite) { - listReason = CHECK; - checkOverwrite = false; - sendCommand(FISH_LIST,E(url.path())); - } - sendCommand(FISH_COPY,E(src.path()),E(url.path())); - if (permissions > -1) sendCommand(FISH_CHMOD,E(TQString::number(permissions,8)),E(url.path())); - } - run(); -} -/** removes a file or directory */ -void fishProtocol::del(const KURL &u, bool isFile){ - myDebug( << "@@@@@@@@@ del " << u << " " << isFile << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - url.cleanPath(); - if (!url.hasPath()) { - sendCommand(FISH_PWD); - } else { - sendCommand((isFile?FISH_DELE:FISH_RMD),E(url.path())); - } - run(); -} -/** special like background execute */ -void fishProtocol::special( const TQByteArray &data ){ - int tmp; - - TQDataStream stream(data, IO_ReadOnly); - - stream >> tmp; - switch (tmp) { - case FISH_EXEC_CMD: // SSH EXEC - { - KURL u; - TQString command; - TQString tempfile; - stream >> u; - stream >> command; - myDebug( << "@@@@@@@@@ exec " << u << " " << command << endl); - setHost(u.host(),u.port(),u.user(),u.pass()); - url = u; - openConnection(); - if (!isLoggedIn) return; - sendCommand(FISH_EXEC,E(command),E(url.path())); - run(); - break; - } - default: - // Some command we don't understand. - error(ERR_UNSUPPORTED_ACTION,TQString().setNum(tmp)); - break; - } -} -/** report status */ -void fishProtocol::slave_status() { - myDebug( << "@@@@@@@@@ slave_status" << endl); - if (childPid > 0) - slaveStatus(connectionHost,isLoggedIn); - else - slaveStatus(TQString::null,false); -} |