summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordscho <dscho>2005-09-28 16:51:50 +0000
committerdscho <dscho>2005-09-28 16:51:50 +0000
commit0a909fde7a283fb22c22bbdbc16bcf4c0fe391ec (patch)
tree9de5c473941fc3c2525a7cbc67fc416cee11efc0
parent93be927b1c1c74bc4da6f6d5978ba8e6e52f3cc2 (diff)
downloadlibtdevnc-0a909fde.tar.gz
libtdevnc-0a909fde.zip
This monster commit contains support for TightVNC's file transfer protocol.
Thank you very much, Rohit!
-rw-r--r--AUTHORS3
-rw-r--r--ChangeLog6
-rw-r--r--configure.ac8
-rw-r--r--examples/.cvsignore1
-rw-r--r--examples/Makefile.am7
-rw-r--r--examples/filetransfer.c11
-rw-r--r--libvncclient/.cvsignore2
-rw-r--r--libvncserver/.cvsignore1
-rw-r--r--libvncserver/Makefile.am19
-rwxr-xr-xlibvncserver/auth.c2
-rw-r--r--libvncserver/cargs.c2
-rw-r--r--libvncserver/main.c40
-rw-r--r--libvncserver/rfbserver.c35
-rwxr-xr-xlibvncserver/sockets.c8
-rw-r--r--libvncserver/tightvnc-filetransfer/.cvsignore3
-rw-r--r--libvncserver/tightvnc-filetransfer/Makefile.am15
-rw-r--r--libvncserver/tightvnc-filetransfer/filelistinfo.c130
-rw-r--r--libvncserver/tightvnc-filetransfer/filelistinfo.h61
-rw-r--r--libvncserver/tightvnc-filetransfer/filetransfermsg.c632
-rw-r--r--libvncserver/tightvnc-filetransfer/filetransfermsg.h54
-rw-r--r--libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c988
-rw-r--r--libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h47
-rw-r--r--libvncserver/tightvnc-filetransfer/rfbtightproto.h450
-rw-r--r--libvncserver/tightvnc-filetransfer/rfbtightserver.c506
-rw-r--r--rfb/rfb.h20
25 files changed, 3025 insertions, 26 deletions
diff --git a/AUTHORS b/AUTHORS
index dcecd8c..8813d17 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,6 +19,9 @@ original proof-of-concept. It really deserves to replace the old version,
as it is a state-of-the-art, fast and usable program by now! However, he
maintains it and improves it still in amazing ways!
+The file transfer protocol from TightVNC was implemented by Rohit Kumar.
+This includes an implementation of RFB protocol version 3.7t.
+
Occasional important patches were sent by (in order I found the names in my
archives and please don't beat me, if I forgot you, but just send me an
email!): Akira Hatakeyama, Karl J. Runge, Justin "Zippy" Dearing,
diff --git a/ChangeLog b/ChangeLog
index 17a6187..d252555 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-09-28 Rohit Kumar <rokumar@novell.com>
+ * examples/filetransfer.c, rfb/rfb.h, configure.ac,
+ libvncserver/{auth,cargs,main,rfbserver,sockets}.c,
+ libvncserver/tightvnc-extension/*:
+ Implement TightVNC's file transfer protocol.
+
2005-09-27 Rohit Kumar <rokumar@novell.com>
* libvncserver/{cargs,sockets,main,rfbserver}.c,
rfb/rfb.h: Provide a generic means to extend the RFB
diff --git a/configure.ac b/configure.ac
index f134de5..84079ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,14 @@ AC_PATH_PROG([AR], [ar], [/usr/bin/ar],
[$PATH:/usr/ccs/bin])
# Options
+AH_TEMPLATE(WITH_TIGHTVNC_FILETRANSFER, [Disable TightVNCFileTransfer protocol])
+AC_ARG_WITH(tightvnc-filetransfer,
+ [ --without-filetransfer disable TightVNC file transfer protocol],
+ , [ with_tightvnc_filetransfer=yes ])
+if test "x$with_tightvnc_filetransfer" == "xyes"; then
+ AC_DEFINE(WITH_TIGHTVNC_FILETRANSFER)
+fi
+AM_CONDITIONAL(WITH_TIGHTVNC_FILETRANSFER, test "$with_tightvnc_filetransfer" == "yes")
AH_TEMPLATE(BACKCHANNEL, [Enable BackChannel communication])
AC_ARG_WITH(backchannel,
[ --without-backchannel disable backchannel method],
diff --git a/examples/.cvsignore b/examples/.cvsignore
index b88a4db..7d110e0 100644
--- a/examples/.cvsignore
+++ b/examples/.cvsignore
@@ -13,4 +13,5 @@ simple15
colourmaptest
regiontest
mac
+filetransfer
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 468e223..614c5ff 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -6,9 +6,14 @@ MAC=mac
mac_LDFLAGS=-framework ApplicationServices -framework Carbon -framework IOKit
endif
+if WITH_TIGHTVNC_FILETRANSFER
+FILETRANSFER=filetransfer
+endif
+
noinst_HEADERS=radon.h
noinst_PROGRAMS=example pnmshow regiontest pnmshow24 fontsel \
- vncev storepasswd colourmaptest simple simple15 $(MAC)
+ vncev storepasswd colourmaptest simple simple15 $(MAC) \
+ $(FILETRANSFER)
diff --git a/examples/filetransfer.c b/examples/filetransfer.c
new file mode 100644
index 0000000..dacf73d
--- /dev/null
+++ b/examples/filetransfer.c
@@ -0,0 +1,11 @@
+#include <rfb/rfb.h>
+
+int main(int argc,char** argv)
+{
+ rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,400,300,8,3,4);
+ server->frameBuffer=(char*)malloc(400*300*4);
+ rfbRegisterTightVNCFileTransferExtension();
+ rfbInitServer(server);
+ rfbRunEventLoop(server,-1,FALSE);
+ return(0);
+}
diff --git a/libvncclient/.cvsignore b/libvncclient/.cvsignore
index ac15bd3..d498e83 100644
--- a/libvncclient/.cvsignore
+++ b/libvncclient/.cvsignore
@@ -1,5 +1,5 @@
.deps
Makefile
Makefile.in
-client_test
+libvncclient.a
diff --git a/libvncserver/.cvsignore b/libvncserver/.cvsignore
index 09653e9..c892af4 100644
--- a/libvncserver/.cvsignore
+++ b/libvncserver/.cvsignore
@@ -1,4 +1,5 @@
.deps
Makefile
Makefile.in
+libvncserver.a
diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am
index 13bcb84..ecffba1 100644
--- a/libvncserver/Makefile.am
+++ b/libvncserver/Makefile.am
@@ -1,4 +1,16 @@
-DEFINES=-g -Wall
+AM_CFLAGS=-g -Wall
+
+#if WITH_TIGHTVNC_FILETRANSFER
+TIGHTVNCFILETRANSFERHDRS=tightvnc-filetransfer/filelistinfo.h \
+ tightvnc-filetransfer/filetransfermsg.h \
+ tightvnc-filetransfer/handlefiletransferrequest.h \
+ tightvnc-filetransfer/rfbtightproto.h
+
+TIGHTVNCFILETRANSFERSRCS = tightvnc-filetransfer/rfbtightserver.c \
+ tightvnc-filetransfer/handlefiletransferrequest.c \
+ tightvnc-filetransfer/filetransfermsg.c \
+ tightvnc-filetransfer/filelistinfo.c
+#endif
includedir=$(prefix)/include/rfb
#include_HEADERS=rfb.h rfbconfig.h rfbint.h rfbproto.h keysym.h rfbregion.h
@@ -7,7 +19,8 @@ include_HEADERS=../rfb/rfb.h ../rfb/rfbconfig.h ../rfb/rfbint.h \
../rfb/rfbproto.h ../rfb/keysym.h ../rfb/rfbregion.h ../rfb/rfbclient.h
noinst_HEADERS=d3des.h ../rfb/default8x16.h zrleoutstream.h \
- zrlepalettehelper.h zrletypes.h private.h
+ zrlepalettehelper.h zrletypes.h private.h \
+ $(TIGHTVNCFILETRANSFERHDRS)
EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \
tableinitcmtemplate.c tabletrans24template.c \
@@ -24,7 +37,7 @@ LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c \
stats.c corre.c hextile.c rre.c translate.c cutpaste.c \
httpd.c cursor.c font.c \
draw.c selbox.c d3des.c vncauth.c cargs.c \
- $(ZLIBSRCS) $(JPEGSRCS)
+ $(ZLIBSRCS) $(JPEGSRCS) $(TIGHTVNCFILETRANSFERSRCS)
libvncserver_a_SOURCES=$(LIB_SRCS)
diff --git a/libvncserver/auth.c b/libvncserver/auth.c
index e8de22f..5c1c044 100755
--- a/libvncserver/auth.c
+++ b/libvncserver/auth.c
@@ -207,7 +207,7 @@ rfbAuthNewClient(rfbClientPtr cl)
void
rfbProcessClientSecurityType(rfbClientPtr cl)
{
- int n, i;
+ int n;
uint8_t chosenType;
rfbSecurityHandler* handler;
diff --git a/libvncserver/cargs.c b/libvncserver/cargs.c
index 10926a9..96b9f84 100644
--- a/libvncserver/cargs.c
+++ b/libvncserver/cargs.c
@@ -151,7 +151,7 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[])
for(extension=rfbGetExtensionIterator();handled==0 && extension;
extension=extension->next)
if(extension->processArgument)
- handled = extension->processArgument(argv + i);
+ handled = extension->processArgument(*argc - i, argv + i);
rfbReleaseExtensionIterator();
if(handled==0) {
diff --git a/libvncserver/main.c b/libvncserver/main.c
index 905bb83..240d50d 100644
--- a/libvncserver/main.c
+++ b/libvncserver/main.c
@@ -84,6 +84,46 @@ void rfbReleaseExtensionIterator()
UNLOCK(extMutex);
}
+rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
+ void* data)
+{
+ rfbExtensionData* extData;
+
+ /* make sure extension is not yet enabled. */
+ for(extData = cl->extensions; extData; extData = extData->next)
+ if(extData->extension == extension)
+ return FALSE;
+
+ extData = calloc(sizeof(rfbExtensionData),1);
+ extData->extension = extension;
+ extData->data = data;
+ extData->next = cl->extensions;
+ cl->extensions = extData;
+
+ return TRUE;
+}
+
+rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension)
+{
+ rfbExtensionData* extData;
+ rfbExtensionData* prevData = NULL;
+
+ for(extData = cl->extensions; extData; extData = extData->next) {
+ if(extData->extension == extension) {
+ if(extData->data)
+ free(extData->data);
+ if(prevData == NULL)
+ cl->extensions = extData->next;
+ else
+ prevData->next = extData->next;
+ return TRUE;
+ }
+ prevData = extData;
+ }
+
+ return FALSE;
+}
+
/*
* Logging
*/
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
index 730c789..0c25f80 100644
--- a/libvncserver/rfbserver.c
+++ b/libvncserver/rfbserver.c
@@ -229,6 +229,7 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
rfbClientPtr cl,cl_;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
+ rfbProtocolExtension* extension;
cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1);
@@ -361,6 +362,16 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
}
}
+ for(extension = rfbGetExtensionIterator(); extension;
+ extension=extension->next) {
+ void* data = NULL;
+ /* if the extension does not have a newClient method, it wants
+ * to be initialized later. */
+ if(extension->newClient && extension->newClient(cl, &data))
+ rfbEnableExtension(cl, extension, data);
+ }
+ rfbReleaseExtensionIterator();
+
switch (cl->screen->newClientHook(cl)) {
case RFB_CLIENT_ON_HOLD:
cl->onHold = TRUE;
@@ -606,7 +617,7 @@ rfbProcessClientInitMessage(rfbClientPtr cl)
int len, n;
rfbClientIteratorPtr iterator;
rfbClientPtr otherCl;
- rfbProtocolExtension* extension;
+ rfbExtensionData* extension;
if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
if (n == 0)
@@ -636,18 +647,14 @@ rfbProcessClientInitMessage(rfbClientPtr cl)
return;
}
- for(extension=rfbGetExtensionIterator();extension;extension=extension->next)
- if(extension->init) {
- void* data;
- if(extension->init(cl, &data)) {
- rfbExtensionData* extensionData=calloc(sizeof(rfbExtensionData),1);
- extensionData->extension=extension;
- extensionData->data=data;
- extensionData->next=cl->extensions;
- cl->extensions=extensionData;
- }
- }
- rfbReleaseExtensionIterator();
+ for(extension = cl->extensions; extension;) {
+ rfbExtensionData* next = extension->next;
+ if(extension->extension->init &&
+ !extension->extension->init(cl, extension->data))
+ /* extension requested that it be removed */
+ rfbDisableExtension(cl, extension->extension);
+ extension = next;
+ }
cl->state = RFB_NORMAL;
@@ -1068,7 +1075,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
for(extension=cl->extensions; extension; extension=extension->next)
if(extension->extension->handleMessage &&
- extension->extension->handleMessage(cl, extension->data, msg))
+ extension->extension->handleMessage(cl, extension->data, &msg))
return;
if(cl->screen->processCustomClientMessage(cl,msg.type)) {
diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c
index 44843c2..ca8b995 100755
--- a/libvncserver/sockets.c
+++ b/libvncserver/sockets.c
@@ -466,6 +466,14 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
}
}
}
+#undef DEBUG_READ_EXACT
+#ifdef DEBUG_READ_EXACT
+ rfbLog("ReadExact %d bytes\n",len);
+ for(n=0;n<len;n++)
+ fprintf(stderr,"%02x ",(unsigned char)buf[n]);
+ fprintf(stderr,"\n");
+#endif
+
return 1;
}
diff --git a/libvncserver/tightvnc-filetransfer/.cvsignore b/libvncserver/tightvnc-filetransfer/.cvsignore
new file mode 100644
index 0000000..22a4e72
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+
diff --git a/libvncserver/tightvnc-filetransfer/Makefile.am b/libvncserver/tightvnc-filetransfer/Makefile.am
new file mode 100644
index 0000000..be93e5f
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/Makefile.am
@@ -0,0 +1,15 @@
+DEFINES=-g -Wall
+
+includedir=$(prefix)/include/rfb
+
+noinst_HEADERS=filelistinfo.h filetransfermsg.h \
+ handlefiletransferrequest.h rfbtightproto.h
+
+LIB_SRCS = rfbtightserver.c handlefiletransferrequest.c filetransfermsg.c \
+ filelistinfo.c
+
+tightvnc_filetransfer_a_SOURCES=$(LIB_SRCS)
+
+lib_LIBRARIES=tightvnc-filetransfer.a
+
+
diff --git a/libvncserver/tightvnc-filetransfer/filelistinfo.c b/libvncserver/tightvnc-filetransfer/filelistinfo.c
new file mode 100644
index 0000000..8b482a1
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/filelistinfo.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+
+#include <stdio.h>
+#include "rfb/rfb.h"
+#include "filelistinfo.h"
+
+
+/* This method is used for debugging purpose */
+void
+DisplayFileList(FileListInfo fli)
+{
+ int i = 0;
+ if((fli.pEntries == NULL) || (fli.numEntries == 0)) return;
+
+ rfbLog("DISPLAYING FILE NAMES IN THE LIST ...START\n\n");
+ rfbLog("Numer of entries:: %d\n", fli.numEntries);
+ for(i = 0; i < fli.numEntries; i++)
+ rfbLog("file[%d]\t<%s>\n", i, fli.pEntries[i].name);
+ rfbLog("DISPLAYING FILE NAMES IN THE LIST ...END\n\n");
+}
+
+
+int
+AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name,
+ unsigned int size, unsigned int data)
+{
+ FileListItemInfoPtr fileListItemInfoPtr = (FileListItemInfoPtr)
+ calloc((fileListInfoPtr->numEntries + 1),
+ sizeof(FileListItemInfo));
+ if(fileListItemInfoPtr == NULL) {
+ rfbLog("File [%s]: Method [%s]: fileListItemInfoPtr is NULL\n",
+ __FILE__, __FUNCTION__);
+ return FAILURE;
+ }
+
+ if(fileListInfoPtr->numEntries != 0) {
+ memcpy(fileListItemInfoPtr, fileListInfoPtr->pEntries,
+ fileListInfoPtr->numEntries * sizeof(FileListItemInfo));
+ }
+
+ strcpy(fileListItemInfoPtr[fileListInfoPtr->numEntries].name, name);
+ fileListItemInfoPtr[fileListInfoPtr->numEntries].size = size;
+ fileListItemInfoPtr[fileListInfoPtr->numEntries].data = data;
+
+ if(fileListInfoPtr->pEntries != NULL) {
+ free(fileListInfoPtr->pEntries);
+ fileListInfoPtr->pEntries = NULL;
+ }
+
+ fileListInfoPtr->pEntries = fileListItemInfoPtr;
+ fileListItemInfoPtr = NULL;
+ fileListInfoPtr->numEntries++;
+
+ return SUCCESS;
+}
+
+
+char*
+GetFileNameAt(FileListInfo fileListInfo, int number)
+{
+ char* name = NULL;
+ if(number >= 0 && number < fileListInfo.numEntries)
+ name = fileListInfo.pEntries[number].name;
+ return name;
+}
+
+
+unsigned int
+GetFileSizeAt(FileListInfo fileListInfo, int number)
+{
+ unsigned int size = 0;
+ if(number >= 0 && number < fileListInfo.numEntries)
+ size = fileListInfo.pEntries[number].size;
+ return size;
+}
+
+
+unsigned int
+GetFileDataAt(FileListInfo fileListInfo, int number)
+{
+ unsigned int data = 0;
+ if(number >= 0 && number < fileListInfo.numEntries)
+ data = fileListInfo.pEntries[number].data;
+ return data;
+}
+
+
+unsigned int
+GetSumOfFileNamesLength(FileListInfo fileListInfo)
+{
+ int i = 0, sumLen = 0;
+ for(i = 0; i < fileListInfo.numEntries; i++)
+ sumLen += strlen(fileListInfo.pEntries[i].name);
+ return sumLen;
+}
+
+
+void
+FreeFileListInfo(FileListInfo fileListInfo)
+{
+ if(fileListInfo.pEntries != NULL) {
+ free(fileListInfo.pEntries);
+ fileListInfo.pEntries = NULL;
+ }
+ fileListInfo.numEntries = 0;
+}
+
diff --git a/libvncserver/tightvnc-filetransfer/filelistinfo.h b/libvncserver/tightvnc-filetransfer/filelistinfo.h
new file mode 100644
index 0000000..543edbe
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/filelistinfo.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+
+#ifndef FILE_LIST_INFO_H
+#define FILE_LIST_INFO_H
+
+#include <limits.h>
+
+
+#define SUCCESS 1
+#define FAILURE 0
+
+typedef struct _FileListItemInfo {
+ char name[NAME_MAX];
+ unsigned int size;
+ unsigned int data;
+} FileListItemInfo, *FileListItemInfoPtr;
+
+typedef struct _FileListItemSize {
+ unsigned int size;
+ unsigned int data;
+} FileListItemSize, *FileListItemSizePtr;
+
+typedef struct _FileListInfo {
+ FileListItemInfoPtr pEntries;
+ int numEntries;
+} FileListInfo, *FileListInfoPtr;
+
+int AddFileListItemInfo(FileListInfoPtr fileListInfoPtr, char* name, unsigned int size, unsigned int data);
+char* GetFileNameAt(FileListInfo fileListInfo, int number);
+unsigned int GetFileSizeAt(FileListInfo fileListInfo, int number);
+unsigned int GetFileDataAt(FileListInfo fileListInfo, int number);
+unsigned int GetSumOfFileNamesLength(FileListInfo fileListInfo);
+void FreeFileListInfo(FileListInfo fileListInfo);
+
+void DisplayFileList(FileListInfo fli);
+
+#endif
+
diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c
new file mode 100644
index 0000000..6a3a39e
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <utime.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <rfb/rfb.h>
+#include "rfbtightproto.h"
+#include "filelistinfo.h"
+#include "filetransfermsg.h"
+#include "handlefiletransferrequest.h"
+
+#define SZ_RFBBLOCKSIZE 8192
+
+
+void
+FreeFileTransferMsg(FileTransferMsg ftm)
+{
+
+ if(ftm.data != NULL) {
+ free(ftm.data);
+ ftm.data = NULL;
+ }
+
+ ftm.length = 0;
+
+}
+
+
+/******************************************************************************
+ * Methods to handle file list request.
+ ******************************************************************************/
+
+int CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag);
+FileTransferMsg CreateFileListErrMsg(char flags);
+FileTransferMsg CreateFileListMsg(FileListInfo fileListInfo, char flags);
+
+
+/*
+ * This is the method called by HandleFileListRequest to get the file list
+ */
+
+FileTransferMsg
+GetFileListResponseMsg(char* path, char flags)
+{
+ FileTransferMsg fileListMsg;
+ FileListInfo fileListInfo;
+ int status = -1;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+ memset(&fileListInfo, 0, sizeof(FileListInfo));
+
+
+ /* fileListInfo can have null data if the folder is Empty
+ or if some error condition has occured.
+ The return value is 'failure' only if some error condition has occured.
+ */
+ status = CreateFileListInfo(&fileListInfo, path, !(flags & 0x10));
+
+ if(status == FAILURE) {
+ fileListMsg = CreateFileListErrMsg(flags);
+ }
+ else {
+ /* DisplayFileList(fileListInfo); For Debugging */
+
+ fileListMsg = CreateFileListMsg(fileListInfo, flags);
+ FreeFileListInfo(fileListInfo);
+ }
+
+ return fileListMsg;
+}
+
+
+int
+CreateFileListInfo(FileListInfoPtr pFileListInfo, char* path, int flag)
+{
+ DIR* pDir = NULL;
+ struct dirent* pDirent = NULL;
+
+ if((path == NULL) || (strlen(path) == 0)) {
+ /* In this case we will send the list of entries in ftp root*/
+ sprintf(path, "%s%s", GetFtpRoot(), "/");
+ }
+
+ if((pDir = opendir(path)) == NULL) {
+ rfbLog("File [%s]: Method [%s]: not able to open the dir\n",
+ __FILE__, __FUNCTION__);
+ return FAILURE;
+ }
+
+ while((pDirent = readdir(pDir))) {
+ if(strcmp(pDirent->d_name, ".") && strcmp(pDirent->d_name, "..")) {
+ struct stat stat_buf;
+ /*
+ int fpLen = sizeof(char)*(strlen(pDirent->d_name)+strlen(path)+2);
+ */
+ char fullpath[PATH_MAX];
+
+ memset(fullpath, 0, PATH_MAX);
+
+ strcpy(fullpath, path);
+ if(path[strlen(path)-1] != '/')
+ strcat(fullpath, "/");
+ strcat(fullpath, pDirent->d_name);
+
+ if(stat(fullpath, &stat_buf) < 0) {
+ rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
+ __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+
+ if(S_ISDIR(stat_buf.st_mode)) {
+ if(AddFileListItemInfo(pFileListInfo, pDirent->d_name, -1, 0) == 0) {
+ rfbLog("File [%s]: Method [%s]: Add directory %s in the"
+ " list failed\n", __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+ }
+ else {
+ if(flag) {
+ if(AddFileListItemInfo(pFileListInfo, pDirent->d_name,
+ stat_buf.st_size,
+ stat_buf.st_mtime) == 0) {
+ rfbLog("File [%s]: Method [%s]: Add file %s in the "
+ "list failed\n", __FILE__, __FUNCTION__, fullpath);
+ continue;
+ }
+ }
+ }
+ }
+ }
+ if(closedir(pDir) < 0) {
+ rfbLog("File [%s]: Method [%s]: ERROR Couldn't close dir\n",
+ __FILE__, __FUNCTION__);
+ }
+
+ return SUCCESS;
+}
+
+
+FileTransferMsg
+CreateFileListErrMsg(char flags)
+{
+ FileTransferMsg fileListMsg;
+ rfbFileListDataMsg* pFLD = NULL;
+ char* data = NULL;
+ unsigned int length = 0;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+
+ data = (char*) calloc(sizeof(rfbFileListDataMsg), sizeof(char));
+ if(data == NULL) {
+ return fileListMsg;
+ }
+ length = sizeof(rfbFileListDataMsg) * sizeof(char);
+ pFLD = (rfbFileListDataMsg*) data;
+
+ pFLD->type = rfbFileListData;
+ pFLD->numFiles = Swap16IfLE(0);
+ pFLD->dataSize = Swap16IfLE(0);
+ pFLD->compressedSize = Swap16IfLE(0);
+ pFLD->flags = flags | 0x80;
+
+ fileListMsg.data = data;
+ fileListMsg.length = length;
+
+ return fileListMsg;
+}
+
+
+FileTransferMsg
+CreateFileListMsg(FileListInfo fileListInfo, char flags)
+{
+ FileTransferMsg fileListMsg;
+ rfbFileListDataMsg* pFLD = NULL;
+ char *data = NULL, *pFileNames = NULL;
+ unsigned int length = 0, dsSize = 0, i = 0;
+ FileListItemSizePtr pFileListItemSize = NULL;
+
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+ dsSize = fileListInfo.numEntries * 8;
+ length = sz_rfbFileListDataMsg + dsSize +
+ GetSumOfFileNamesLength(fileListInfo) +
+ fileListInfo.numEntries;
+
+ data = (char*) calloc(length, sizeof(char));
+ if(data == NULL) {
+ return fileListMsg;
+ }
+ pFLD = (rfbFileListDataMsg*) data;
+ pFileListItemSize = (FileListItemSizePtr) &data[sz_rfbFileListDataMsg];
+ pFileNames = &data[sz_rfbFileListDataMsg + dsSize];
+
+ pFLD->type = rfbFileListData;
+ pFLD->flags = flags & 0xF0;
+ pFLD->numFiles = Swap16IfLE(fileListInfo.numEntries);
+ pFLD->dataSize = Swap16IfLE(GetSumOfFileNamesLength(fileListInfo) +
+ fileListInfo.numEntries);
+ pFLD->compressedSize = pFLD->dataSize;
+
+ for(i =0; i <fileListInfo.numEntries; i++) {
+ pFileListItemSize[i].size = Swap32IfLE(GetFileSizeAt(fileListInfo, i));
+ pFileListItemSize[i].data = Swap32IfLE(GetFileDataAt(fileListInfo, i));
+ strcpy(pFileNames, GetFileNameAt(fileListInfo, i));
+
+ if(i+1 < fileListInfo.numEntries)
+ pFileNames += strlen(pFileNames) + 1;
+ }
+
+ fileListMsg.data = data;
+ fileListMsg.length = length;
+
+ return fileListMsg;
+}
+
+
+/******************************************************************************
+ * Methods to handle File Download Request.
+ ******************************************************************************/
+
+FileTransferMsg CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen);
+FileTransferMsg CreateFileDownloadZeroSizeDataMsg(unsigned long mTime);
+FileTransferMsg CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile);
+
+FileTransferMsg
+GetFileDownLoadErrMsg()
+{
+ FileTransferMsg fileDownloadErrMsg;
+
+ char reason[] = "An internal error on the server caused download failure";
+ int reasonLen = strlen(reason);
+
+ memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
+
+ fileDownloadErrMsg = CreateFileDownloadErrMsg(reason, reasonLen);
+
+ return fileDownloadErrMsg;
+}
+
+
+FileTransferMsg
+GetFileDownloadReadDataErrMsg()
+{
+ char reason[] = "Cannot open file, perhaps it is absent or is a directory";
+ int reasonLen = strlen(reason);
+
+ return CreateFileDownloadErrMsg(reason, reasonLen);
+
+}
+
+
+FileTransferMsg
+GetFileDownloadLengthErrResponseMsg()
+{
+ char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
+ int reasonLen = strlen(reason);
+
+ return CreateFileDownloadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ //const unsigned int sz_rfbBlockSize = SZ_RFBBLOCKSIZE;
+ int numOfBytesRead = 0;
+ char pBuf[SZ_RFBBLOCKSIZE];
+ char* path = rtcp->rcft.rcfd.fName;
+
+ memset(pBuf, 0, SZ_RFBBLOCKSIZE);
+
+ if((rtcp->rcft.rcfd.downloadInProgress == FALSE) && (rtcp->rcft.rcfd.downloadFD == -1)) {
+ if((rtcp->rcft.rcfd.downloadFD = open(path, O_RDONLY)) == -1) {
+ rfbLog("File [%s]: Method [%s]: Error: Couldn't open file\n",
+ __FILE__, __FUNCTION__);
+ return GetFileDownloadReadDataErrMsg();
+ }
+ rtcp->rcft.rcfd.downloadInProgress = TRUE;
+ }
+ if((rtcp->rcft.rcfd.downloadInProgress == TRUE) && (rtcp->rcft.rcfd.downloadFD != -1)) {
+ if( (numOfBytesRead = read(rtcp->rcft.rcfd.downloadFD, pBuf, SZ_RFBBLOCKSIZE)) <= 0) {
+ close(rtcp->rcft.rcfd.downloadFD);
+ rtcp->rcft.rcfd.downloadFD = -1;
+ rtcp->rcft.rcfd.downloadInProgress = FALSE;
+ if(numOfBytesRead == 0) {
+ return CreateFileDownloadZeroSizeDataMsg(rtcp->rcft.rcfd.mTime);
+ }
+ return GetFileDownloadReadDataErrMsg();
+ }
+ return CreateFileDownloadBlockSizeDataMsg(numOfBytesRead, pBuf);
+ }
+}
+
+
+FileTransferMsg
+ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ FileTransferMsg fileDownloadMsg;
+ struct stat stat_buf;
+ int sz_rfbFileSize = 0;
+ char* path = rtcp->rcft.rcfd.fName;
+
+ memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
+
+ if( (path == NULL) || (strlen(path) == 0) ||
+ (stat(path, &stat_buf) < 0) || (!(S_ISREG(stat_buf.st_mode))) ) {
+
+ char reason[] = "Cannot open file, perhaps it is absent or is not a regular file";
+ int reasonLen = strlen(reason);
+
+ rfbLog("File [%s]: Method [%s]: Reading stat for path %s failed\n",
+ __FILE__, __FUNCTION__, path);
+
+ fileDownloadMsg = CreateFileDownloadErrMsg(reason, reasonLen);
+ }
+ else {
+ rtcp->rcft.rcfd.mTime = stat_buf.st_mtime;
+ sz_rfbFileSize = stat_buf.st_size;
+ if(sz_rfbFileSize <= 0) {
+ fileDownloadMsg = CreateFileDownloadZeroSizeDataMsg(stat_buf.st_mtime);
+ }
+
+ }
+ return fileDownloadMsg;
+}
+
+
+FileTransferMsg
+CreateFileDownloadErrMsg(char* reason, unsigned int reasonLen)
+{
+ FileTransferMsg fileDownloadErrMsg;
+ int length = sz_rfbFileDownloadFailedMsg + reasonLen + 1;
+ rfbFileDownloadFailedMsg *pFDF = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadErrMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadErrMsg;
+ }
+
+ pFDF = (rfbFileDownloadFailedMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadFailedMsg];
+
+ pFDF->type = rfbFileDownloadFailed;
+ pFDF->reasonLen = Swap16IfLE(reasonLen);
+ memcpy(pFollow, reason, reasonLen);
+
+ fileDownloadErrMsg.data = pData;
+ fileDownloadErrMsg.length = length;
+
+ return fileDownloadErrMsg;
+}
+
+
+FileTransferMsg
+CreateFileDownloadZeroSizeDataMsg(unsigned long mTime)
+{
+ FileTransferMsg fileDownloadZeroSizeDataMsg;
+ int length = sz_rfbFileDownloadDataMsg + sizeof(int);
+ rfbFileDownloadDataMsg *pFDD = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadZeroSizeDataMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadZeroSizeDataMsg;
+ }
+
+ pFDD = (rfbFileDownloadDataMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadDataMsg];
+
+ pFDD->type = rfbFileDownloadData;
+ pFDD->compressLevel = 0;
+ pFDD->compressedSize = Swap16IfLE(0);
+ pFDD->realSize = Swap16IfLE(0);
+
+ memcpy(pFollow, &mTime, sizeof(unsigned long));
+
+ fileDownloadZeroSizeDataMsg.data = pData;
+ fileDownloadZeroSizeDataMsg.length = length;
+
+ return fileDownloadZeroSizeDataMsg;
+
+}
+
+
+FileTransferMsg
+CreateFileDownloadBlockSizeDataMsg(unsigned short sizeFile, char *pFile)
+{
+ FileTransferMsg fileDownloadBlockSizeDataMsg;
+ int length = sz_rfbFileDownloadDataMsg + sizeFile;
+ rfbFileDownloadDataMsg *pFDD = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileDownloadBlockSizeDataMsg, 0, sizeof(FileTransferMsg));
+ if(NULL == pData) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileDownloadBlockSizeDataMsg;
+ }
+
+ pFDD = (rfbFileDownloadDataMsg *) pData;
+ pFollow = &pData[sz_rfbFileDownloadDataMsg];
+
+ pFDD->type = rfbFileDownloadData;
+ pFDD->compressLevel = 0;
+ pFDD->compressedSize = Swap16IfLE(sizeFile);
+ pFDD->realSize = Swap16IfLE(sizeFile);
+
+ memcpy(pFollow, pFile, sizeFile);
+
+ fileDownloadBlockSizeDataMsg.data = pData;
+ fileDownloadBlockSizeDataMsg.length = length;
+
+ return fileDownloadBlockSizeDataMsg;
+
+}
+
+
+/******************************************************************************
+ * Methods to handle file upload request
+ ******************************************************************************/
+
+FileTransferMsg CreateFileUploadErrMsg(char* reason, unsigned int reasonLen);
+
+FileTransferMsg
+GetFileUploadLengthErrResponseMsg()
+{
+ char reason [] = "Path length exceeds PATH_MAX (4096) bytes";
+ int reasonLen = strlen(reason);
+
+ return CreateFileUploadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ FileTransferMsg fileUploadErrMsg;
+
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+ if( (rtcp->rcft.rcfu.fName == NULL) ||
+ (strlen(rtcp->rcft.rcfu.fName) == 0) ||
+ ((rtcp->rcft.rcfu.uploadFD = creat(rtcp->rcft.rcfu.fName,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)) {
+
+ char reason[] = "Could not create file";
+ int reasonLen = strlen(reason);
+ fileUploadErrMsg = CreateFileUploadErrMsg(reason, reasonLen);
+ }
+ else
+ rtcp->rcft.rcfu.uploadInProgress = TRUE;
+
+ return fileUploadErrMsg;
+}
+
+
+FileTransferMsg
+GetFileUploadCompressedLevelErrMsg()
+{
+ char reason[] = "Server does not support data compression on upload";
+ int reasonLen = strlen(reason);
+
+ return CreateFileUploadErrMsg(reason, reasonLen);
+}
+
+
+FileTransferMsg
+ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
+{
+ FileTransferMsg ftm;
+ unsigned long numOfBytesWritten = 0;
+
+ memset(&ftm, 0, sizeof(FileTransferMsg));
+
+ numOfBytesWritten = write(rtcp->rcft.rcfu.uploadFD, pBuf, rtcp->rcft.rcfu.fSize);
+
+ if(numOfBytesWritten != rtcp->rcft.rcfu.fSize) {
+ char reason[] = "Error writing file data";
+ int reasonLen = strlen(reason);
+ ftm = CreateFileUploadErrMsg(reason, reasonLen);
+ CloseUndoneFileTransfer(cl, rtcp);
+ }
+ return ftm;
+}
+
+
+void
+FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ /* Here we are settimg the modification and access time of the file */
+ /* Windows code stes mod/access/creation time of the file */
+ struct utimbuf utb;
+
+ utb.actime = utb.modtime = rtcp->rcft.rcfu.mTime;
+ if(utime(rtcp->rcft.rcfu.fName, &utb) == -1) {
+ rfbLog("File [%s]: Method [%s]: Setting the modification/access"
+ " time for the file <%s> failed\n", __FILE__,
+ __FUNCTION__, rtcp->rcft.rcfu.fName);
+ }
+
+ if(rtcp->rcft.rcfu.uploadFD != -1) {
+ close(rtcp->rcft.rcfu.uploadFD);
+ rtcp->rcft.rcfu.uploadFD = -1;
+ rtcp->rcft.rcfu.uploadInProgress = FALSE;
+ }
+}
+
+
+FileTransferMsg
+CreateFileUploadErrMsg(char* reason, unsigned int reasonLen)
+{
+ FileTransferMsg fileUploadErrMsg;
+ int length = sz_rfbFileUploadCancelMsg + reasonLen;
+ rfbFileUploadCancelMsg *pFDF = NULL;
+ char *pFollow = NULL;
+
+ char *pData = (char*) calloc(length, sizeof(char));
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+ if(pData == NULL) {
+ rfbLog("File [%s]: Method [%s]: pData is NULL\n",
+ __FILE__, __FUNCTION__);
+ return fileUploadErrMsg;
+ }
+
+ pFDF = (rfbFileUploadCancelMsg *) pData;
+ pFollow = &pData[sz_rfbFileUploadCancelMsg];
+
+ pFDF->type = rfbFileUploadCancel;
+ pFDF->reasonLen = Swap16IfLE(reasonLen);
+ memcpy(pFollow, reason, reasonLen);
+
+ fileUploadErrMsg.data = pData;
+ fileUploadErrMsg.length = length;
+
+ return fileUploadErrMsg;
+}
+
+
+/******************************************************************************
+ * Method to cancel File Transfer operation.
+ ******************************************************************************/
+
+void
+CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ /* TODO :: File Upload case is not handled currently */
+ /* TODO :: In case of concurrency we need to use Critical Section */
+
+ if(cl == NULL)
+ return;
+
+
+ if(rtcp->rcft.rcfu.uploadInProgress == TRUE) {
+ rtcp->rcft.rcfu.uploadInProgress = FALSE;
+
+ if(rtcp->rcft.rcfu.uploadFD != -1) {
+ close(rtcp->rcft.rcfu.uploadFD);
+ rtcp->rcft.rcfu.uploadFD = -1;
+ }
+
+ if(unlink(rtcp->rcft.rcfu.fName) == -1) {
+ rfbLog("File [%s]: Method [%s]: Delete operation on file <%s> failed\n",
+ __FILE__, __FUNCTION__, rtcp->rcft.rcfu.fName);
+ }
+
+ memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX);
+ }
+
+ if(rtcp->rcft.rcfd.downloadInProgress == TRUE) {
+ rtcp->rcft.rcfd.downloadInProgress = FALSE;
+
+ if(rtcp->rcft.rcfd.downloadFD != -1) {
+ close(rtcp->rcft.rcfd.downloadFD);
+ rtcp->rcft.rcfd.downloadFD = -1;
+ }
+ memset(rtcp->rcft.rcfd.fName, 0 , PATH_MAX);
+ }
+}
+
+
+/******************************************************************************
+ * Method to handle create directory request.
+ ******************************************************************************/
+
+void
+CreateDirectory(char* dirName)
+{
+ if(dirName == NULL) return;
+
+ if(mkdir(dirName, 0700) == -1) {
+ rfbLog("File [%s]: Method [%s]: Create operation for directory <%s> failed\n",
+ __FILE__, __FUNCTION__, dirName);
+ }
+}
+
diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.h b/libvncserver/tightvnc-filetransfer/filetransfermsg.h
new file mode 100644
index 0000000..30e58df
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+
+#ifndef FILE_TRANSFER_MSG_H
+#define FILE_TRANSFER_MSG_H
+
+typedef struct _FileTransferMsg {
+ char* data;
+ unsigned int length;
+} FileTransferMsg;
+
+FileTransferMsg GetFileListResponseMsg(char* path, char flag);
+
+FileTransferMsg GetFileDownloadResponseMsg(char* path);
+FileTransferMsg GetFileDownloadLengthErrResponseMsg();
+FileTransferMsg GetFileDownLoadErrMsg();
+FileTransferMsg GetFileDownloadResponseMsgInBlocks(rfbClientPtr cl, rfbTightClientPtr data);
+FileTransferMsg ChkFileDownloadErr(rfbClientPtr cl, rfbTightClientPtr data);
+
+FileTransferMsg GetFileUploadLengthErrResponseMsg();
+FileTransferMsg GetFileUploadCompressedLevelErrMsg();
+FileTransferMsg ChkFileUploadErr(rfbClientPtr cl, rfbTightClientPtr data);
+FileTransferMsg ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr data, char* pBuf);
+
+void CreateDirectory(char* dirName);
+void FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr data);
+void CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr data);
+
+void FreeFileTransferMsg(FileTransferMsg ftm);
+
+#endif
+
diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c
new file mode 100644
index 0000000..d9165ef
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <rfb/rfb.h>
+#include "rfbtightproto.h"
+#include "filetransfermsg.h"
+#include "handlefiletransferrequest.h"
+
+
+pthread_mutex_t fileDownloadMutex = PTHREAD_MUTEX_INITIALIZER;
+
+rfbBool fileTransferEnabled = TRUE;
+rfbBool fileTransferInitted = FALSE;
+char ftproot[PATH_MAX];
+
+
+/******************************************************************************
+ * File Transfer Init methods. These methods are called for initializating
+ * File Transfer and setting ftproot.
+ ******************************************************************************/
+
+void InitFileTransfer();
+int SetFtpRoot(char* path);
+char* GetHomeDir(uid_t uid);
+void FreeHomeDir(char *homedir);
+
+/*
+ * InitFileTransfer method is called before parsing the command-line options
+ * for Xvnc. This sets the ftproot to the Home dir of the user running the Xvnc
+ * server. In case of error ftproot is set to '\0' char.
+ */
+
+void
+InitFileTransfer()
+{
+ char* userHome = NULL;
+ uid_t uid = geteuid();
+
+ if(fileTransferInitted)
+ return;
+
+ memset(ftproot, 0, sizeof(ftproot));
+
+ userHome = GetHomeDir(uid);
+
+ if((userHome != NULL) && (strlen(userHome) != 0)) {
+ SetFtpRoot(userHome);
+ FreeHomeDir(userHome);
+ }
+
+ fileTransferEnabled = TRUE;
+ fileTransferInitted = TRUE;
+}
+
+
+/*
+ * This method is called from InitFileTransfer method and
+ * if the command line option for ftproot is provided.
+ */
+int
+SetFtpRoot(char* path)
+{
+ struct stat stat_buf;
+ DIR* dir = NULL;
+
+ if((path == NULL) || (strlen(path) == 0) || (strlen(path) > (PATH_MAX - 1))) {
+ rfbLog("File [%s]: Method [%s]: parameter passed is improper, ftproot"
+ " not changed\n", __FILE__, __FUNCTION__);
+ return FALSE;
+ }
+
+ if(stat(path, &stat_buf) < 0) {
+ rfbLog("File [%s]: Method [%s]: Reading stat for file %s failed\n",
+ __FILE__, __FUNCTION__, path);
+ return FALSE;
+ }
+
+ if(S_ISDIR(stat_buf.st_mode) == 0) {
+ rfbLog("File [%s]: Method [%s]: path specified is not a directory\n",
+ __FILE__, __FUNCTION__);
+ return FALSE;
+ }
+
+ if((dir = opendir(path)) == NULL) {
+ rfbLog("File [%s]: Method [%s]: Not able to open the directory\n",
+ __FILE__, __FUNCTION__);
+ return FALSE;
+ }
+ else {
+ closedir(dir);
+ dir = NULL;
+ }
+
+
+ memset(ftproot, 0, PATH_MAX);
+ if(path[strlen(path)-1] == '/') {
+ memcpy(ftproot, path, strlen(path)-1);
+ }
+ else
+ memcpy(ftproot, path, strlen(path));
+
+
+ return TRUE;
+}
+
+
+/*
+ * Get the home directory for the user name
+ * param: username - name of the user for whom the home directory is required.
+ * returns: returns the home directory for the user, or null in case the entry
+ * is not found or any error. The returned string must be freed by calling the
+ * freehomedir function.
+*/
+char*
+GetHomeDir(uid_t uid)
+{
+ struct passwd *pwEnt = NULL;
+ char *homedir = NULL;
+
+ pwEnt = getpwuid (uid);
+ if (pwEnt == NULL)
+ return NULL;
+
+ if(pwEnt->pw_dir != NULL) {
+ homedir = strdup (pwEnt->pw_dir);
+ }
+
+ return homedir;
+}
+
+
+/*
+ * Free the home directory allocated by a previous call to retrieve the home
+ * directory. param: homedir - the string returned by a previous call to
+ * retrieve home directory for a user.
+ */
+void
+FreeHomeDir(char *homedir)
+{
+ free (homedir);
+}
+
+
+/******************************************************************************
+ * General methods.
+ ******************************************************************************/
+
+/*
+ * When the console sends the File Transfer Request, it sends the file path with
+ * ftproot as "/". So on Agent, to get the absolute file path we need to prepend
+ * the ftproot to it.
+ */
+char*
+ConvertPath(char* path)
+{
+ char p[PATH_MAX];
+ memset(p, 0, PATH_MAX);
+
+ if( (path == NULL) ||
+ (strlen(path) == 0) ||
+ (strlen(path)+strlen(ftproot) > PATH_MAX - 1) ) {
+
+ rfbLog("File [%s]: Method [%s]: cannot create path for file transfer\n",
+ __FILE__, __FUNCTION__);
+ return NULL;
+ }
+
+ memcpy(p, path, strlen(path));
+ memset(path, 0, PATH_MAX);
+ sprintf(path, "%s%s", ftproot, p);
+
+ return path;
+}
+
+
+void
+EnableFileTransfer(rfbBool enable)
+{
+ fileTransferEnabled = enable;
+}
+
+
+rfbBool
+IsFileTransferEnabled()
+{
+ return fileTransferEnabled;
+}
+
+
+char*
+GetFtpRoot()
+{
+ return ftproot;
+}
+
+
+/******************************************************************************
+ * Methods to Handle File List Request.
+ ******************************************************************************/
+
+/*
+ * HandleFileListRequest method is called when the server receives
+ * FileListRequest. In case of success a file list is sent to the client.
+ * For File List Request there is no failure reason sent.So here in case of any
+ * "unexpected" error no information will be sent. As these conditions should
+ * never come. Lets hope it never arrives :)
+ * In case of dir open failure an empty list will be sent, just the header of
+ * the message filled up. So on console you will get an Empty listing.
+ */
+void
+HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data)
+{
+ rfbClientToServerTightMsg msg;
+ int n = 0;
+ char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
+ FileTransferMsg fileListMsg;
+
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+ memset(path, 0, PATH_MAX);
+ memset(&fileListMsg, 0, sizeof(FileTransferMsg));
+
+ if(cl == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileListRequestMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Socket error while reading dir name"
+ " length\n", __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.flr.dirNameSize = Swap16IfLE(msg.flr.dirNameSize);
+ if ((msg.flr.dirNameSize == 0) ||
+ (msg.flr.dirNameSize > (PATH_MAX - 1))) {
+
+ rfbLog("File [%s]: Method [%s]: Unexpected error:: path length is "
+ "greater that PATH_MAX\n", __FILE__, __FUNCTION__);
+
+ return;
+ }
+
+ if((n = rfbReadExact(cl, path, msg.flr.dirNameSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Socket error while reading dir name\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(ConvertPath(path) == NULL) {
+
+ /* The execution should never reach here */
+ rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ fileListMsg = GetFileListResponseMsg(path, (char) (msg.flr.flags));
+
+ if((fileListMsg.data == NULL) || (fileListMsg.length == 0)) {
+
+ rfbLog("File [%s]: Method [%s]: Unexpected error:: Data to be sent is "
+ "of Zero length\n", __FILE__, __FUNCTION__);
+ return;
+ }
+
+ rfbWriteExact(cl, fileListMsg.data, fileListMsg.length);
+
+ FreeFileTransferMsg(fileListMsg);
+}
+
+
+/******************************************************************************
+ * Methods to Handle File Download Request.
+ ******************************************************************************/
+
+void HandleFileDownloadLengthError(rfbClientPtr cl, short fNameSize);
+void SendFileDownloadLengthErrMsg(rfbClientPtr cl);
+void HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr data);
+#ifdef TODO
+void HandleFileDownloadRequest(rfbClientPtr cl);
+void SendFileDownloadErrMsg(rfbClientPtr cl);
+void* RunFileDownloadThread(void* client);
+#endif
+
+/*
+ * HandleFileDownloadRequest method is called when the server receives
+ * rfbFileDownload request message.
+ */
+void
+HandleFileDownloadRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
+ rfbClientToServerTightMsg msg;
+
+ memset(path, 0, sizeof(path));
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if(cl == NULL) {
+
+ rfbLog("File [%s]: Method [%s]: Unexpected error:: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileDownloadRequestMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading dir name length\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fdr.fNameSize = Swap16IfLE(msg.fdr.fNameSize);
+ msg.fdr.position = Swap16IfLE(msg.fdr.position);
+
+ if ((msg.fdr.fNameSize == 0) ||
+ (msg.fdr.fNameSize > (PATH_MAX - 1))) {
+
+ rfbLog("File [%s]: Method [%s]: Error: path length is greater than"
+ " PATH_MAX\n", __FILE__, __FUNCTION__);
+
+ HandleFileDownloadLengthError(cl, msg.fdr.fNameSize);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, rtcp->rcft.rcfd.fName, msg.fdr.fNameSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading dir name length\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+ rtcp->rcft.rcfd.fName[msg.fdr.fNameSize] = '\0';
+
+ if(ConvertPath(rtcp->rcft.rcfd.fName) == NULL) {
+
+ rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL",
+ __FILE__, __FUNCTION__);
+
+
+ /* This condition can come only if the file path is greater than
+ PATH_MAX. So sending file path length error msg back to client.
+ */
+
+ SendFileDownloadLengthErrMsg(cl);
+ return;
+ }
+
+ HandleFileDownload(cl, rtcp);
+
+}
+
+
+void
+HandleFileDownloadLengthError(rfbClientPtr cl, short fNameSize)
+{
+ char *path = NULL;
+ int n = 0;
+
+ if((path = (char*) calloc(fNameSize, sizeof(char))) == NULL) {
+ rfbLog("File [%s]: Method [%s]: Fatal Error: Alloc failed\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+ if((n = rfbReadExact(cl, path, fNameSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading dir name\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+
+ if(path != NULL) {
+ free(path);
+ path = NULL;
+ }
+
+ return;
+ }
+
+ if(path != NULL) {
+ free(path);
+ path = NULL;
+ }
+
+ SendFileDownloadLengthErrMsg(cl);
+}
+
+
+void
+SendFileDownloadLengthErrMsg(rfbClientPtr cl)
+{
+ FileTransferMsg fileDownloadErrMsg;
+
+ memset(&fileDownloadErrMsg, 0 , sizeof(FileTransferMsg));
+
+ fileDownloadErrMsg = GetFileDownloadLengthErrResponseMsg();
+
+ if((fileDownloadErrMsg.data == NULL) || (fileDownloadErrMsg.length == 0)) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: fileDownloadErrMsg "
+ "is null\n", __FILE__, __FUNCTION__);
+ return;
+ }
+
+ rfbWriteExact(cl, fileDownloadErrMsg.data, fileDownloadErrMsg.length);
+
+ FreeFileTransferMsg(fileDownloadErrMsg);
+}
+
+extern rfbTightClientPtr rfbGetTightClientData(rfbClientPtr cl);
+
+void*
+RunFileDownloadThread(void* client)
+{
+ rfbClientPtr cl = (rfbClientPtr) client;
+ rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
+ FileTransferMsg fileDownloadMsg;
+
+ if(rtcp == NULL)
+ return NULL;
+
+ memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
+ do {
+ pthread_mutex_lock(&fileDownloadMutex);
+ fileDownloadMsg = GetFileDownloadResponseMsgInBlocks(cl, rtcp);
+ pthread_mutex_unlock(&fileDownloadMutex);
+
+ if((fileDownloadMsg.data != NULL) && (fileDownloadMsg.length != 0)) {
+ if(rfbWriteExact(cl, fileDownloadMsg.data, fileDownloadMsg.length) < 0) {
+ rfbLog("File [%s]: Method [%s]: Error while writing to socket \n"
+ , __FILE__, __FUNCTION__);
+
+ if(cl != NULL) {
+ rfbCloseClient(cl);
+ CloseUndoneFileTransfer(cl, rtcp);
+ }
+
+ FreeFileTransferMsg(fileDownloadMsg);
+ return NULL;
+ }
+ FreeFileTransferMsg(fileDownloadMsg);
+ }
+ } while(rtcp->rcft.rcfd.downloadInProgress == TRUE);
+ return NULL;
+}
+
+
+void
+HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ pthread_t fileDownloadThread;
+ FileTransferMsg fileDownloadMsg;
+
+ memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg));
+ fileDownloadMsg = ChkFileDownloadErr(cl, rtcp);
+ if((fileDownloadMsg.data != NULL) && (fileDownloadMsg.length != 0)) {
+ rfbWriteExact(cl, fileDownloadMsg.data, fileDownloadMsg.length);
+ FreeFileTransferMsg(fileDownloadMsg);
+ return;
+ }
+ rtcp->rcft.rcfd.downloadInProgress = FALSE;
+ rtcp->rcft.rcfd.downloadFD = -1;
+
+ if(pthread_create(&fileDownloadThread, NULL, RunFileDownloadThread, (void*)
+ cl) != 0) {
+ FileTransferMsg ftm = GetFileDownLoadErrMsg();
+
+ rfbLog("File [%s]: Method [%s]: Download thread creation failed\n",
+ __FILE__, __FUNCTION__);
+
+ if((ftm.data != NULL) && (ftm.length != 0)) {
+ rfbWriteExact(cl, ftm.data, ftm.length);
+ FreeFileTransferMsg(ftm);
+ return;
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+ * Methods to Handle File Download Cancel Request.
+ ******************************************************************************/
+
+
+void
+HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char *reason = NULL;
+ rfbClientToServerTightMsg msg;
+
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileDownloadCancelMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading "
+ "FileDownloadCancelMsg\n", __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fdc.reasonLen = Swap16IfLE(msg.fdc.reasonLen);
+
+ if(msg.fdc.reasonLen == 0) {
+ rfbLog("File [%s]: Method [%s]: reason length received is Zero\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ reason = (char*) calloc(msg.fdc.reasonLen + 1, sizeof(char));
+ if(reason == NULL) {
+ rfbLog("File [%s]: Method [%s]: Fatal Error: Memory alloc failed\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, reason, msg.fdc.reasonLen)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading "
+ "FileDownloadCancelMsg\n", __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ }
+
+ rfbLog("File [%s]: Method [%s]: File Download Cancel Request received:"
+ " reason <%s>\n", __FILE__, __FUNCTION__, reason);
+
+ pthread_mutex_lock(&fileDownloadMutex);
+ CloseUndoneFileTransfer(cl, rtcp);
+ pthread_mutex_unlock(&fileDownloadMutex);
+
+ if(reason != NULL) {
+ free(reason);
+ reason = NULL;
+ }
+
+}
+
+
+/******************************************************************************
+ * Methods to Handle File upload request
+ ******************************************************************************/
+
+#ifdef TODO
+void HandleFileUploadRequest(rfbClientPtr cl);
+#endif
+void HandleFileUpload(rfbClientPtr cl, rfbTightClientPtr data);
+void HandleFileUploadLengthError(rfbClientPtr cl, short fNameSize);
+void SendFileUploadLengthErrMsg(rfbClientPtr cl);
+
+
+void
+HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char path[PATH_MAX]; /* PATH_MAX has the value 4096 and is defined in limits.h */
+ rfbClientToServerTightMsg msg;
+
+ memset(path, 0, PATH_MAX);
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if(cl == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadRequestMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fupr.fNameSize = Swap16IfLE(msg.fupr.fNameSize);
+ msg.fupr.position = Swap16IfLE(msg.fupr.position);
+
+ if ((msg.fupr.fNameSize == 0) ||
+ (msg.fupr.fNameSize > (PATH_MAX - 1))) {
+
+ rfbLog("File [%s]: Method [%s]: error: path length is greater than PATH_MAX\n",
+ __FILE__, __FUNCTION__);
+ HandleFileUploadLengthError(cl, msg.fupr.fNameSize);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, rtcp->rcft.rcfu.fName, msg.fupr.fNameSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n"
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+ rtcp->rcft.rcfu.fName[msg.fupr.fNameSize] = '\0';
+
+ if(ConvertPath(rtcp->rcft.rcfu.fName) == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL\n",
+ __FILE__, __FUNCTION__);
+
+ /* This may come if the path length exceeds PATH_MAX.
+ So sending path length error to client
+ */
+ SendFileUploadLengthErrMsg(cl);
+ return;
+ }
+
+ HandleFileUpload(cl, rtcp);
+}
+
+
+void
+HandleFileUploadLengthError(rfbClientPtr cl, short fNameSize)
+{
+ char *path = NULL;
+ int n = 0;
+
+ if((path = (char*) calloc(fNameSize, sizeof(char))) == NULL) {
+ rfbLog("File [%s]: Method [%s]: Fatal Error: Alloc failed\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+ if((n = rfbReadExact(cl, path, fNameSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading dir name\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+
+ if(path != NULL) {
+ free(path);
+ path = NULL;
+ }
+
+ return;
+ }
+
+ rfbLog("File [%s]: Method [%s]: File Upload Length Error occured"
+ "file path requested is <%s>\n", __FILE__, __FUNCTION__, path);
+
+ if(path != NULL) {
+ free(path);
+ path = NULL;
+ }
+
+ SendFileUploadLengthErrMsg(cl);
+}
+
+void
+SendFileUploadLengthErrMsg(rfbClientPtr cl)
+{
+
+ FileTransferMsg fileUploadErrMsg;
+
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+ fileUploadErrMsg = GetFileUploadLengthErrResponseMsg();
+
+ if((fileUploadErrMsg.data == NULL) || (fileUploadErrMsg.length == 0)) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: fileUploadErrMsg is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ rfbWriteExact(cl, fileUploadErrMsg.data, fileUploadErrMsg.length);
+ FreeFileTransferMsg(fileUploadErrMsg);
+}
+
+void
+HandleFileUpload(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ FileTransferMsg fileUploadErrMsg;
+
+ memset(&fileUploadErrMsg, 0, sizeof(FileTransferMsg));
+
+ rtcp->rcft.rcfu.uploadInProgress = FALSE;
+ rtcp->rcft.rcfu.uploadFD = -1;
+
+ fileUploadErrMsg = ChkFileUploadErr(cl, rtcp);
+ if((fileUploadErrMsg.data != NULL) && (fileUploadErrMsg.length != 0)) {
+ rfbWriteExact(cl, fileUploadErrMsg.data, fileUploadErrMsg.length);
+ FreeFileTransferMsg(fileUploadErrMsg);
+ }
+}
+
+
+/******************************************************************************
+ * Methods to Handle File Upload Data Request
+ *****************************************************************************/
+
+void HandleFileUploadWrite(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf);
+
+
+void
+HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char* pBuf = NULL;
+ rfbClientToServerTightMsg msg;
+
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if(cl == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadDataMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fud.realSize = Swap16IfLE(msg.fud.realSize);
+ msg.fud.compressedSize = Swap16IfLE(msg.fud.compressedSize);
+ if((msg.fud.realSize == 0) && (msg.fud.compressedSize == 0)) {
+ if((n = rfbReadExact(cl, (char*)&(rtcp->rcft.rcfu.mTime), sizeof(unsigned
+ long))) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ FileUpdateComplete(cl, rtcp);
+ return;
+ }
+
+ pBuf = (char*) calloc(msg.fud.compressedSize, sizeof(char));
+ if(pBuf == NULL) {
+ rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__);
+ return;
+ }
+ if((n = rfbReadExact(cl, pBuf, msg.fud.compressedSize)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadRequestMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+
+ if(pBuf != NULL) {
+ free(pBuf);
+ pBuf = NULL;
+ }
+
+ return;
+ }
+ if(msg.fud.compressedLevel != 0) {
+ FileTransferMsg ftm;
+ memset(&ftm, 0, sizeof(FileTransferMsg));
+
+ ftm = GetFileUploadCompressedLevelErrMsg();
+
+ if((ftm.data != NULL) && (ftm.length != 0)) {
+ rfbWriteExact(cl, ftm.data, ftm.length);
+ FreeFileTransferMsg(ftm);
+ }
+
+ CloseUndoneFileTransfer(cl, rtcp);
+
+ if(pBuf != NULL) {
+ free(pBuf);
+ pBuf = NULL;
+ }
+
+ return;
+ }
+
+ rtcp->rcft.rcfu.fSize = msg.fud.compressedSize;
+
+ HandleFileUploadWrite(cl, rtcp, pBuf);
+
+ if(pBuf != NULL) {
+ free(pBuf);
+ pBuf = NULL;
+ }
+
+}
+
+
+void
+HandleFileUploadWrite(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf)
+{
+ FileTransferMsg ftm;
+ memset(&ftm, 0, sizeof(FileTransferMsg));
+
+ ftm = ChkFileUploadWriteErr(cl, rtcp, pBuf);
+
+ if((ftm.data != NULL) && (ftm.length != 0)) {
+ rfbWriteExact(cl, ftm.data, ftm.length);
+ FreeFileTransferMsg(ftm);
+ }
+}
+
+
+/******************************************************************************
+ * Methods to Handle File Upload Failed Request.
+ ******************************************************************************/
+
+
+void
+HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char* reason = NULL;
+ rfbClientToServerTightMsg msg;
+
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if(cl == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileUploadFailedMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fuf.reasonLen = Swap16IfLE(msg.fuf.reasonLen);
+ if(msg.fuf.reasonLen == 0) {
+ rfbLog("File [%s]: Method [%s]: reason length received is Zero\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+
+ reason = (char*) calloc(msg.fuf.reasonLen + 1, sizeof(char));
+ if(reason == NULL) {
+ rfbLog("File [%s]: Method [%s]: Memory alloc failed\n", __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, reason, msg.fuf.reasonLen)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+
+ if(reason != NULL) {
+ free(reason);
+ reason = NULL;
+ }
+
+ return;
+ }
+
+ rfbLog("File [%s]: Method [%s]: File Upload Failed Request received:"
+ " reason <%s>\n", __FILE__, __FUNCTION__, reason);
+
+ CloseUndoneFileTransfer(cl, rtcp);
+
+ if(reason != NULL) {
+ free(reason);
+ reason = NULL;
+ }
+
+}
+
+
+/******************************************************************************
+ * Methods to Handle File Create Request.
+ ******************************************************************************/
+
+
+void
+HandleFileCreateDirRequest(rfbClientPtr cl, rfbTightClientPtr rtcp)
+{
+ int n = 0;
+ char dirName[PATH_MAX];
+ rfbClientToServerTightMsg msg;
+
+ memset(dirName, 0, PATH_MAX);
+ memset(&msg, 0, sizeof(rfbClientToServerTightMsg));
+
+ if(cl == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: rfbClientPtr is null\n",
+ __FILE__, __FUNCTION__);
+ return;
+ }
+
+ if((n = rfbReadExact(cl, ((char *)&msg)+1, sz_rfbFileCreateDirRequestMsg-1)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileCreateDirRequestMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.fcdr.dNameLen = Swap16IfLE(msg.fcdr.dNameLen);
+
+ /* TODO :: chk if the dNameLen is greater than PATH_MAX */
+
+ if((n = rfbReadExact(cl, dirName, msg.fcdr.dNameLen)) <= 0) {
+
+ if (n < 0)
+ rfbLog("File [%s]: Method [%s]: Error while reading FileUploadFailedMsg\n",
+ __FILE__, __FUNCTION__);
+
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if(ConvertPath(dirName) == NULL) {
+ rfbLog("File [%s]: Method [%s]: Unexpected error: path is NULL\n",
+ __FILE__, __FUNCTION__);
+
+ return;
+ }
+
+ CreateDirectory(dirName);
+}
+
+
diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h
new file mode 100644
index 0000000..74c0e8a
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 14th July 2005
+ */
+
+#ifndef HANDLE_FILE_TRANSFER_REQUEST_H
+#define HANDLE_FILE_TRANSFER_REQUEST_H
+
+
+#include <rfb/rfb.h>
+
+
+void InitFileTransfer();
+int SetFtpRoot(char* path);
+void EnableFileTransfer(rfbBool enable);
+rfbBool IsFileTransferEnabled();
+char* GetFtpRoot();
+
+void HandleFileListRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileDownloadRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileUploadRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientRec* data);
+void HandleFileCreateDirRequest(rfbClientPtr cl, rfbTightClientRec* data);
+
+#endif
+
diff --git a/libvncserver/tightvnc-filetransfer/rfbtightproto.h b/libvncserver/tightvnc-filetransfer/rfbtightproto.h
new file mode 100644
index 0000000..397daba
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/rfbtightproto.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 25th August 2005
+ */
+
+#ifndef RFBTIGHTPROTO_H
+#define RFBTIGHTPROTO_H
+
+#include <rfb/rfb.h>
+#include <limits.h>
+
+#define rfbSecTypeTight 16
+
+void rfbTightUsage(void);
+int rfbTightProcessArgs(int argc, char *argv[]);
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Tunneling Capabilities (protocol version 3.7t)
+ *
+ * If the chosen security type is rfbSecTypeTight, the server sends a list of
+ * supported tunneling methods ("tunneling" refers to any additional layer of
+ * data transformation, such as encryption or external compression.)
+ *
+ * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported tunneling methods in the order of preference.
+ *
+ * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+ * used, and the client should not send a response requesting a tunneling
+ * method.
+ */
+
+typedef struct _rfbTunnelingCapsMsg {
+ uint32_t nTunnelTypes;
+ /* followed by nTunnelTypes * rfbCapabilityInfo structures */
+} rfbTunnelingCapsMsg;
+
+#define sz_rfbTunnelingCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Tunneling Method Request (protocol version 3.7t)
+ *
+ * If the list of tunneling capabilities sent by the server was not empty, the
+ * client should reply with a 32-bit code specifying a particular tunneling
+ * method. The following code should be used for no tunneling.
+ */
+
+#define rfbNoTunneling 0
+#define sig_rfbNoTunneling "NOTUNNEL"
+
+
+/*-----------------------------------------------------------------------------
+ * Negotiation of Authentication Capabilities (protocol version 3.7t)
+ *
+ * After setting up tunneling, the server sends a list of supported
+ * authentication schemes.
+ *
+ * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+ * that list all supported authentication schemes in the order of preference.
+ *
+ * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+ * necessary, and the client should not send a response requesting an
+ * authentication scheme.
+ */
+
+typedef struct _rfbAuthenticationCapsMsg {
+ uint32_t nAuthTypes;
+ /* followed by nAuthTypes * rfbCapabilityInfo structures */
+} rfbAuthenticationCapsMsg;
+
+#define sz_rfbAuthenticationCapsMsg 4
+
+/*-----------------------------------------------------------------------------
+ * Authentication Scheme Request (protocol version 3.7t)
+ *
+ * If the list of authentication capabilities sent by the server was not empty,
+ * the client should reply with a 32-bit code specifying a particular
+ * authentication scheme. The following codes are supported.
+ */
+
+#define rfbAuthNone 1
+#define rfbAuthVNC 2
+#define rfbAuthUnixLogin 129
+#define rfbAuthExternal 130
+
+#define sig_rfbAuthNone "NOAUTH__"
+#define sig_rfbAuthVNC "VNCAUTH_"
+#define sig_rfbAuthUnixLogin "ULGNAUTH"
+#define sig_rfbAuthExternal "XTRNAUTH"
+
+/*-----------------------------------------------------------------------------
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol version 3.7t).
+ */
+
+typedef struct _rfbCapabilityInfo {
+
+ uint32_t code; /* numeric identifier */
+ uint8_t vendorSignature[4]; /* vendor identification */
+ uint8_t nameSignature[8]; /* abbreviated option name */
+
+} rfbCapabilityInfo;
+
+#define sz_rfbCapabilityInfoVendor 4
+#define sz_rfbCapabilityInfoName 8
+#define sz_rfbCapabilityInfo 16
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define rfbStandardVendor "STDV"
+#define rfbTridiaVncVendor "TRDV"
+#define rfbTightVncVendor "TGHT"
+
+
+/* It's a good idea to keep these values a bit greater than required. */
+#define MAX_TIGHT_ENCODINGS 10
+#define MAX_TUNNELING_CAPS 16
+#define MAX_AUTH_CAPS 16
+
+typedef struct _rfbClientFileDownload {
+ char fName[PATH_MAX];
+ int downloadInProgress;
+ unsigned long mTime;
+ int downloadFD;
+} rfbClientFileDownload ;
+
+typedef struct _rfbClientFileUpload {
+ char fName[PATH_MAX];
+ int uploadInProgress;
+ unsigned long mTime;
+ unsigned long fSize;
+ int uploadFD;
+} rfbClientFileUpload ;
+
+typedef struct _rfbClientFileTransfer {
+ rfbClientFileDownload rcfd;
+ rfbClientFileUpload rcfu;
+} rfbClientFileTransfer;
+
+
+typedef struct _rfbTightClientRec {
+
+ /* Lists of capability codes sent to clients. We remember these
+ lists to restrict clients from choosing those tunneling and
+ authentication types that were not advertised. */
+
+ int nAuthCaps;
+ uint32_t authCaps[MAX_AUTH_CAPS];
+
+ /* This is not useful while we don't support tunneling:
+ int nTunnelingCaps;
+ uint32_t tunnelingCaps[MAX_TUNNELING_CAPS]; */
+
+ rfbClientFileTransfer rcft;
+
+} rfbTightClientRec, *rfbTightClientPtr;
+
+/*
+ * Macro to fill in an rfbCapabilityInfo structure (protocol 3.7t).
+ * Normally, using macros is no good, but this macro saves us from
+ * writing constants twice -- it constructs signature names from codes.
+ * Note that "code_sym" argument should be a single symbol, not an expression.
+ */
+
+#define SetCapInfo(cap_ptr, code_sym, vendor) \
+{ \
+ rfbCapabilityInfo *pcap; \
+ pcap = (cap_ptr); \
+ pcap->code = Swap32IfLE(code_sym); \
+ memcpy(pcap->vendorSignature, (vendor), \
+ sz_rfbCapabilityInfoVendor); \
+ memcpy(pcap->nameSignature, sig_##code_sym, \
+ sz_rfbCapabilityInfoName); \
+}
+
+void rfbHandleSecTypeTight(rfbClientPtr cl);
+
+
+/*-----------------------------------------------------------------------------
+ * Server Interaction Capabilities Message (protocol version 3.7t)
+ *
+ * In the protocol version 3.7t, the server informs the client what message
+ * types it supports in addition to ones defined in the protocol version 3.7.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+
+typedef struct _rfbInteractionCapsMsg {
+ uint16_t nServerMessageTypes;
+ uint16_t nClientMessageTypes;
+ uint16_t nEncodingTypes;
+ uint16_t pad; /* reserved, must be 0 */
+ /* followed by nServerMessageTypes * rfbCapabilityInfo structures */
+ /* followed by nClientMessageTypes * rfbCapabilityInfo structures */
+} rfbInteractionCapsMsg;
+
+#define sz_rfbInteractionCapsMsg 8
+
+#define rfbFileListData 130
+#define rfbFileDownloadData 131
+#define rfbFileUploadCancel 132
+#define rfbFileDownloadFailed 133
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListData "FTS_LSDT"
+#define sig_rfbFileDownloadData "FTS_DNDT"
+#define sig_rfbFileUploadCancel "FTS_UPCN"
+#define sig_rfbFileDownloadFailed "FTS_DNFL"
+
+
+
+#define rfbFileListRequest 130
+#define rfbFileDownloadRequest 131
+#define rfbFileUploadRequest 132
+#define rfbFileUploadData 133
+#define rfbFileDownloadCancel 134
+#define rfbFileUploadFailed 135
+#define rfbFileCreateDirRequest 136
+
+/* signatures for non-standard messages */
+#define sig_rfbFileListRequest "FTC_LSRQ"
+#define sig_rfbFileDownloadRequest "FTC_DNRQ"
+#define sig_rfbFileUploadRequest "FTC_UPRQ"
+#define sig_rfbFileUploadData "FTC_UPDT"
+#define sig_rfbFileDownloadCancel "FTC_DNCN"
+#define sig_rfbFileUploadFailed "FTC_UPFL"
+#define sig_rfbFileCreateDirRequest "FTC_FCDR"
+
+
+/* signatures for basic encoding types */
+#define sig_rfbEncodingRaw "RAW_____"
+#define sig_rfbEncodingCopyRect "COPYRECT"
+#define sig_rfbEncodingRRE "RRE_____"
+#define sig_rfbEncodingCoRRE "CORRE___"
+#define sig_rfbEncodingHextile "HEXTILE_"
+#define sig_rfbEncodingZlib "ZLIB____"
+#define sig_rfbEncodingTight "TIGHT___"
+#define sig_rfbEncodingZlibHex "ZLIBHEX_"
+
+
+/* signatures for "fake" encoding types */
+#define sig_rfbEncodingCompressLevel0 "COMPRLVL"
+#define sig_rfbEncodingXCursor "X11CURSR"
+#define sig_rfbEncodingRichCursor "RCHCURSR"
+#define sig_rfbEncodingPointerPos "POINTPOS"
+#define sig_rfbEncodingLastRect "LASTRECT"
+#define sig_rfbEncodingNewFBSize "NEWFBSIZ"
+#define sig_rfbEncodingQualityLevel0 "JPEGQLVL"
+
+
+/*-----------------------------------------------------------------------------
+ * FileListRequest
+ */
+
+typedef struct _rfbFileListRequestMsg {
+ uint8_t type;
+ uint8_t flags;
+ uint16_t dirNameSize;
+ /* Followed by char Dirname[dirNameSize] */
+} rfbFileListRequestMsg;
+
+#define sz_rfbFileListRequestMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadRequest
+ */
+
+typedef struct _rfbFileDownloadRequestMsg {
+ uint8_t type;
+ uint8_t compressedLevel;
+ uint16_t fNameSize;
+ uint32_t position;
+ /* Followed by char Filename[fNameSize] */
+} rfbFileDownloadRequestMsg;
+
+#define sz_rfbFileDownloadRequestMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileUploadRequest
+ */
+
+typedef struct _rfbFileUploadRequestMsg {
+ uint8_t type;
+ uint8_t compressedLevel;
+ uint16_t fNameSize;
+ uint32_t position;
+ /* Followed by char Filename[fNameSize] */
+} rfbFileUploadRequestMsg;
+
+#define sz_rfbFileUploadRequestMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadData
+ */
+
+typedef struct _rfbFileUploadDataMsg {
+ uint8_t type;
+ uint8_t compressedLevel;
+ uint16_t realSize;
+ uint16_t compressedSize;
+ /* Followed by File[compressedSize],
+ but if (realSize = compressedSize = 0) followed by uint32_t modTime */
+} rfbFileUploadDataMsg;
+
+#define sz_rfbFileUploadDataMsg 6
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadCancel
+ */
+
+typedef struct _rfbFileDownloadCancelMsg {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t reasonLen;
+ /* Followed by reason[reasonLen] */
+} rfbFileDownloadCancelMsg;
+
+#define sz_rfbFileDownloadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileUploadFailed
+ */
+
+typedef struct _rfbFileUploadFailedMsg {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t reasonLen;
+ /* Followed by reason[reasonLen] */
+} rfbFileUploadFailedMsg;
+
+#define sz_rfbFileUploadFailedMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileCreateDirRequest
+ */
+
+typedef struct _rfbFileCreateDirRequestMsg {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t dNameLen;
+ /* Followed by dName[dNameLen] */
+} rfbFileCreateDirRequestMsg;
+
+#define sz_rfbFileCreateDirRequestMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union _rfbClientToServerTightMsg {
+ rfbFileListRequestMsg flr;
+ rfbFileDownloadRequestMsg fdr;
+ rfbFileUploadRequestMsg fupr;
+ rfbFileUploadDataMsg fud;
+ rfbFileDownloadCancelMsg fdc;
+ rfbFileUploadFailedMsg fuf;
+ rfbFileCreateDirRequestMsg fcdr;
+} rfbClientToServerTightMsg;
+
+
+
+/*-----------------------------------------------------------------------------
+ * FileListData
+ */
+
+typedef struct _rfbFileListDataMsg {
+ uint8_t type;
+ uint8_t flags;
+ uint16_t numFiles;
+ uint16_t dataSize;
+ uint16_t compressedSize;
+ /* Followed by SizeData[numFiles] */
+ /* Followed by Filenames[compressedSize] */
+} rfbFileListDataMsg;
+
+#define sz_rfbFileListDataMsg 8
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadData
+ */
+
+typedef struct _rfbFileDownloadDataMsg {
+ uint8_t type;
+ uint8_t compressLevel;
+ uint16_t realSize;
+ uint16_t compressedSize;
+ /* Followed by File[copressedSize],
+ but if (realSize = compressedSize = 0) followed by uint32_t modTime */
+} rfbFileDownloadDataMsg;
+
+#define sz_rfbFileDownloadDataMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * FileUploadCancel
+ */
+
+typedef struct _rfbFileUploadCancelMsg {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t reasonLen;
+ /* Followed by reason[reasonLen] */
+} rfbFileUploadCancelMsg;
+
+#define sz_rfbFileUploadCancelMsg 4
+
+/*-----------------------------------------------------------------------------
+ * FileDownloadFailed
+ */
+
+typedef struct _rfbFileDownloadFailedMsg {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t reasonLen;
+ /* Followed by reason[reasonLen] */
+} rfbFileDownloadFailedMsg;
+
+#define sz_rfbFileDownloadFailedMsg 4
+
+
+
+
+#endif
+
+
diff --git a/libvncserver/tightvnc-filetransfer/rfbtightserver.c b/libvncserver/tightvnc-filetransfer/rfbtightserver.c
new file mode 100644
index 0000000..825fce0
--- /dev/null
+++ b/libvncserver/tightvnc-filetransfer/rfbtightserver.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2005 Novell, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail,
+ * you may find current contact information at www.novell.com
+ *
+ * Author : Rohit Kumar
+ * Email ID : rokumar@novell.com
+ * Date : 25th August 2005
+ */
+
+
+#include <rfb/rfb.h>
+#include "rfbtightproto.h"
+#include "handlefiletransferrequest.h"
+
+/*
+ * Get my data!
+ *
+ * This gets the extension specific data from the client structure. If
+ * the data is not found, the client connection is closed, a complaint
+ * is logged, and NULL is returned.
+ */
+
+extern rfbProtocolExtension tightVncFileTransferExtension;
+
+rfbTightClientPtr rfbGetTightClientData(rfbClientPtr cl)
+{
+ rfbExtensionData* data = cl->extensions;
+
+ while(data && data->extension != &tightVncFileTransferExtension)
+ data = data->next;
+
+ if(data == NULL) {
+ rfbLog("TightVNC enabled, but client data missing?!\n");
+ rfbCloseClient(cl);
+ return NULL;
+ }
+
+ return (rfbTightClientPtr)data->data;
+}
+
+/*
+ * Send the authentication challenge.
+ */
+
+static void
+rfbVncAuthSendChallenge(cl)
+ rfbClientPtr cl;
+{
+
+ // 4 byte header is alreay sent. Which is rfbSecTypeVncAuth (same as rfbVncAuth). Just send the challenge.
+ rfbRandomBytes(cl->authChallenge);
+ if (rfbWriteExact(cl, (char *)cl->authChallenge, CHALLENGESIZE) < 0) {
+ rfbLogPerror("rfbAuthNewClient: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Dispatch client input to rfbVncAuthProcessResponse. */
+ /* This methos is defined in auth.c file */
+ rfbAuthProcessClientMessage(cl);
+
+}
+
+/*
+ * Read client's preferred authentication type (protocol 3.7t).
+ */
+
+void
+rfbProcessClientAuthType(cl)
+ rfbClientPtr cl;
+{
+ uint32_t auth_type;
+ int n, i;
+ rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
+
+ if(rtcp == NULL)
+ return;
+
+ /* Read authentication type selected by the client. */
+ n = rfbReadExact(cl, (char *)&auth_type, sizeof(auth_type));
+ if (n <= 0) {
+ if (n == 0)
+ rfbLog("rfbProcessClientAuthType: client gone\n");
+ else
+ rfbLogPerror("rfbProcessClientAuthType: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ auth_type = Swap32IfLE(auth_type);
+
+ /* Make sure it was present in the list sent by the server. */
+ for (i = 0; i < rtcp->nAuthCaps; i++) {
+ if (auth_type == rtcp->authCaps[i])
+ break;
+ }
+ if (i >= rtcp->nAuthCaps) {
+ rfbLog("rfbProcessClientAuthType: "
+ "wrong authentication type requested\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ switch (auth_type) {
+ case rfbAuthNone:
+ /* Dispatch client input to rfbProcessClientInitMessage. */
+ cl->state = RFB_INITIALISATION;
+ break;
+ case rfbAuthVNC:
+ rfbVncAuthSendChallenge(cl);
+ break;
+ default:
+ rfbLog("rfbProcessClientAuthType: unknown authentication scheme\n");
+ rfbCloseClient(cl);
+ }
+}
+
+
+/*
+ * Read tunneling type requested by the client (protocol 3.7t).
+ * NOTE: Currently, we don't support tunneling, and this function
+ * can never be called.
+ */
+
+void
+rfbProcessClientTunnelingType(cl)
+ rfbClientPtr cl;
+{
+ /* If we were called, then something's really wrong. */
+ rfbLog("rfbProcessClientTunnelingType: not implemented\n");
+ rfbCloseClient(cl);
+ return;
+}
+
+
+/*
+ * Send the list of our authentication capabilities to the client
+ * (protocol 3.7t).
+ */
+
+static void
+rfbSendAuthCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbBool authRequired;
+ rfbAuthenticationCapsMsg caps;
+ rfbCapabilityInfo caplist[MAX_AUTH_CAPS];
+ int count = 0;
+ rfbTightClientPtr rtcp = rfbGetTightClientData(cl);
+
+ if(rtcp == NULL)
+ return;
+
+ if (cl->screen->authPasswdData && !cl->reverseConnection) {
+ // chk if this condition is valid or not.
+ SetCapInfo(&caplist[count], rfbAuthVNC, rfbStandardVendor);
+ rtcp->authCaps[count++] = rfbAuthVNC;
+ }
+
+ rtcp->nAuthCaps = count;
+ caps.nAuthTypes = Swap32IfLE((uint32_t)count);
+ if (rfbWriteExact(cl, (char *)&caps, sz_rfbAuthenticationCapsMsg) < 0) {
+ rfbLogPerror("rfbSendAuthCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if (count) {
+ if (rfbWriteExact(cl, (char *)&caplist[0],
+ count * sz_rfbCapabilityInfo) < 0) {
+ rfbLogPerror("rfbSendAuthCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+ /* Dispatch client input to rfbProcessClientAuthType. */
+ /* Call the function for authentication from here */
+ rfbProcessClientAuthType(cl);
+ } else {
+ /* Dispatch client input to rfbProcessClientInitMessage. */
+ cl->state = RFB_INITIALISATION;
+ }
+}
+
+
+
+
+
+/*
+ * Send the list of our tunneling capabilities (protocol 3.7t).
+ */
+
+static void
+rfbSendTunnelingCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbTunnelingCapsMsg caps;
+ uint32_t nTypes = 0; /* we don't support tunneling yet */
+
+ caps.nTunnelTypes = Swap32IfLE(nTypes);
+ if (rfbWriteExact(cl, (char *)&caps, sz_rfbTunnelingCapsMsg) < 0) {
+ rfbLogPerror("rfbSendTunnelingCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ if (nTypes) {
+ /* Dispatch client input to rfbProcessClientTunnelingType(). */
+ /* The flow should not reach here as tunneling is not implemented. */
+ rfbProcessClientTunnelingType(cl);
+ } else {
+ rfbSendAuthCaps(cl);
+ }
+}
+
+
+
+/*
+ * rfbSendInteractionCaps is called after sending the server
+ * initialisation message, only if TightVNC protocol extensions were
+ * enabled (protocol 3.7t). In this function, we send the lists of
+ * supported protocol messages and encodings.
+ */
+
+/* Update these constants on changing capability lists below! */
+/* Values updated for FTP */
+#define N_SMSG_CAPS 4
+#define N_CMSG_CAPS 6
+#define N_ENC_CAPS 12
+
+void
+rfbSendInteractionCaps(cl)
+ rfbClientPtr cl;
+{
+ rfbInteractionCapsMsg intr_caps;
+ rfbCapabilityInfo smsg_list[N_SMSG_CAPS];
+ rfbCapabilityInfo cmsg_list[N_CMSG_CAPS];
+ rfbCapabilityInfo enc_list[N_ENC_CAPS];
+ int i;
+
+ /* Fill in the header structure sent prior to capability lists. */
+ intr_caps.nServerMessageTypes = Swap16IfLE(N_SMSG_CAPS);
+ intr_caps.nClientMessageTypes = Swap16IfLE(N_CMSG_CAPS);
+ intr_caps.nEncodingTypes = Swap16IfLE(N_ENC_CAPS);
+ intr_caps.pad = 0;
+
+ /* Supported server->client message types. */
+ /* For file transfer support: */
+ i = 0;
+ if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
+ SetCapInfo(&smsg_list[i++], rfbFileListData, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileDownloadData, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileUploadCancel, rfbTightVncVendor);
+ SetCapInfo(&smsg_list[i++], rfbFileDownloadFailed, rfbTightVncVendor);
+ if (i != N_SMSG_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_SMSG_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+ }
+
+ /* Supported client->server message types. */
+ /* For file transfer support: */
+ i = 0;
+ if((IsFileTransferEnabled() == TRUE) && ( cl->viewOnly == FALSE)) {
+ SetCapInfo(&cmsg_list[i++], rfbFileListRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileDownloadRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadRequest, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadData, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileDownloadCancel, rfbTightVncVendor);
+ SetCapInfo(&cmsg_list[i++], rfbFileUploadFailed, rfbTightVncVendor);
+ if (i != N_CMSG_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_CMSG_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+ }
+
+ /* Encoding types. */
+ i = 0;
+ SetCapInfo(&enc_list[i++], rfbEncodingCopyRect, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingRRE, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingCoRRE, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingHextile, rfbStandardVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingZlib, rfbTridiaVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingTight, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingCompressLevel0, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingQualityLevel0, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingXCursor, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingRichCursor, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingPointerPos, rfbTightVncVendor);
+ SetCapInfo(&enc_list[i++], rfbEncodingLastRect, rfbTightVncVendor);
+ if (i != N_ENC_CAPS) {
+ rfbLog("rfbSendInteractionCaps: assertion failed, i != N_ENC_CAPS\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Send header and capability lists */
+ if (rfbWriteExact(cl, (char *)&intr_caps,
+ sz_rfbInteractionCapsMsg) < 0 ||
+ rfbWriteExact(cl, (char *)&smsg_list[0],
+ sz_rfbCapabilityInfo * N_SMSG_CAPS) < 0 ||
+ rfbWriteExact(cl, (char *)&cmsg_list[0],
+ sz_rfbCapabilityInfo * N_CMSG_CAPS) < 0 ||
+ rfbWriteExact(cl, (char *)&enc_list[0],
+ sz_rfbCapabilityInfo * N_ENC_CAPS) < 0) {
+ rfbLogPerror("rfbSendInteractionCaps: write");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ /* Dispatch client input to rfbProcessClientNormalMessage(). */
+ cl->state = RFB_NORMAL;
+}
+
+
+
+rfbBool
+rfbTightExtensionInit(cl, data)
+rfbClientPtr cl;
+void** data;
+{
+
+ rfbSendInteractionCaps(cl);
+
+ return TRUE;
+}
+
+static rfbBool
+handleMessage(rfbClientPtr cl,
+ const char* messageName,
+ void (*handler)(rfbClientPtr cl, rfbTightClientPtr data))
+{
+ rfbTightClientPtr data;
+
+ rfbLog("%s message received\n", messageName);
+
+ if((IsFileTransferEnabled() == FALSE) || ( cl->viewOnly == TRUE)) {
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+
+ data = rfbGetTightClientData(cl);
+ if(data == NULL)
+ return FALSE;
+
+ handler(cl, data);
+ return TRUE;
+}
+
+rfbBool
+rfbTightExtensionMsgHandler(cl, data, msg)
+struct _rfbClientRec* cl;
+void* data;
+const rfbClientToServerMsg* msg;
+{
+ switch (msg->type) {
+
+ case rfbFileListRequest:
+
+ return handleMessage(cl, "rfbFileListRequest", HandleFileListRequest);
+
+ case rfbFileDownloadRequest:
+
+ return handleMessage(cl, "rfbFileDownloadRequest", HandleFileDownloadRequest);
+
+ case rfbFileUploadRequest:
+
+ return handleMessage(cl, "rfbFileUploadRequest", HandleFileUploadRequest);
+
+ case rfbFileUploadData:
+
+ return handleMessage(cl, "rfbFileUploadDataRequest", HandleFileUploadDataRequest);
+
+ case rfbFileDownloadCancel:
+
+ return handleMessage(cl, "rfbFileDownloadCancelRequest", HandleFileDownloadCancelRequest);
+
+ case rfbFileUploadFailed:
+
+ return handleMessage(cl, "rfbFileUploadFailedRequest", HandleFileUploadFailedRequest);
+
+ case rfbFileCreateDirRequest:
+
+ return handleMessage(cl, "rfbFileCreateDirRequest", HandleFileCreateDirRequest);
+
+ default:
+
+ rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
+ msg->type);
+
+ /*
+
+ // We shouldn't close the connection here for unhandled msg, it should be left to libvncserver.
+ rfbLog(" ... closing connection\n");
+ rfbCloseClient(cl);
+
+ */
+
+ return FALSE;
+
+ }
+}
+
+
+void
+rfbTightExtensionClientClose(rfbClientPtr cl, void* data) {
+
+ if(data != NULL)
+ free(data);
+
+}
+
+void
+rfbTightUsage(void) {
+ fprintf(stderr, "\nlibvncserver-tight-extension options:\n");
+ fprintf(stderr, "-disablefiletransfer disable file transfer\n");
+ fprintf(stderr, "-ftproot string set ftp root\n");
+ fprintf(stderr,"\n");
+}
+
+int
+rfbTightProcessArg(int argc, char *argv[]) {
+
+ InitFileTransfer();
+
+ if(argc<1)
+ return 0;
+
+ if (strcmp(argv[0], "-ftproot") == 0) { /* -ftproot string */
+ if (2 > argc) {
+ return 0;
+ }
+ rfbLog("ftproot is set to <%s>\n", argv[1]);
+ if(SetFtpRoot(argv[1]) == FALSE) {
+ rfbLog("ERROR:: Path specified for ftproot in invalid\n");
+ return 0;
+ }
+ return 2;
+ } else if (strcmp(argv[0], "-disablefiletransfer") == 0) {
+ EnableFileTransfer(FALSE);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This method should be registered to libvncserver to handle rfbSecTypeTight security type.
+ */
+void
+rfbHandleSecTypeTight(rfbClientPtr cl) {
+
+ rfbTightClientPtr rtcp = (rfbTightClientPtr) malloc(sizeof(rfbTightClientRec));
+
+ if(rtcp == NULL) {
+ // Error condition close socket
+ rfbLog("Memory error has occured while handling Tight security type... closing connection.\n");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ memset(rtcp, 0, sizeof(rfbTightClientRec));
+ rtcp->rcft.rcfd.downloadFD = -1;
+ rtcp->rcft.rcfu.uploadFD = -1;
+ rfbEnableExtension(cl, &tightVncFileTransferExtension, rtcp);
+
+ rfbSendTunnelingCaps(cl);
+
+}
+
+rfbProtocolExtension tightVncFileTransferExtension = {
+ NULL,
+ rfbTightExtensionInit,
+ rfbTightExtensionMsgHandler,
+ rfbTightExtensionClientClose,
+ rfbTightUsage,
+ rfbTightProcessArg,
+ NULL
+};
+
+static rfbSecurityHandler tightVncSecurityHandler = {
+ rfbSecTypeTight,
+ rfbHandleSecTypeTight,
+ NULL
+};
+
+void rfbRegisterTightVNCFileTransferExtension() {
+ rfbRegisterProtocolExtension(&tightVncFileTransferExtension);
+ rfbRegisterSecurityHandler(&tightVncSecurityHandler);
+}
+
+
diff --git a/rfb/rfb.h b/rfb/rfb.h
index bac805c..fa7d7d7 100644
--- a/rfb/rfb.h
+++ b/rfb/rfb.h
@@ -159,16 +159,20 @@ typedef struct _rfbSecurity {
*/
typedef struct _rfbProtocolExtension {
- /* returns TRUE if extension should be activated */
- rfbBool (*init)(struct _rfbClientRec* client, void** data);
+ /* returns FALSE if extension should be deactivated for client.
+ if newClient == NULL, it is always deactivated. */
+ rfbBool (*newClient)(struct _rfbClientRec* client, void** data);
+ /* returns FALSE if extension should be deactivated for client.
+ if init == NULL, it stays activated. */
+ rfbBool (*init)(struct _rfbClientRec* client, void* data);
/* returns TRUE if message was handled */
rfbBool (*handleMessage)(struct _rfbClientRec* client,
void* data,
- rfbClientToServerMsg message);
+ const rfbClientToServerMsg* message);
void (*close)(struct _rfbClientRec* client, void* data);
void (*usage)(void);
/* processArguments returns the number of handled arguments */
- int (*processArgument)(char *argv[]);
+ int (*processArgument)(int argc, char *argv[]);
struct _rfbProtocolExtension* next;
} rfbProtocolExtension;
@@ -623,6 +627,7 @@ extern void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen);
/* auth.c */
extern void rfbAuthNewClient(rfbClientPtr cl);
+extern void rfbProcessClientSecurityType(rfbClientPtr cl);
extern void rfbAuthProcessClientMessage(rfbClientPtr cl);
extern void rfbRegisterSecurityHandler(rfbSecurityHandler* handler);
@@ -788,7 +793,9 @@ enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl);
void rfbRegisterProtocolExtension(rfbProtocolExtension* extension);
struct _rfbProtocolExtension* rfbGetExtensionIterator();
void rfbReleaseExtensionIterator();
-rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension);
+rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
+ void* data);
+rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension);
/* to check against plain passwords */
rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len);
@@ -821,6 +828,9 @@ extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, rfbBool runI
extern rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec);
extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo);
+/* TightVNC file transfer extension */
+void rfbRegisterTightVNCFileTransferExtension();
+
#endif
#if(defined __cplusplus)