diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index c30c46b..4517b07 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -175,8 +175,7 @@ static rfbBool decompStreamInited = FALSE; */ /* Separate buffer for compressed data. */ -// TODO: -// #define ZLIB_BUFFER_SIZE 512 +/* TODO: threading issues */ #define ZLIB_BUFFER_SIZE 30000 static char zlib_buffer[ZLIB_BUFFER_SIZE]; @@ -205,6 +204,33 @@ ConnectToRFBServer(rfbClient* client,const char *hostname, int port) { unsigned int host; + if (client->serverPort==-1) { + /* serverHost is a file recorded by vncrec. */ + const char* magic="vncLog0.0"; + char buffer[10]; + rfbVNCRec* rec = (rfbVNCRec*)malloc(sizeof(rfbVNCRec)); + client->vncRec = rec; + + rec->file = fopen(client->serverHost,"rb"); + rec->tv.tv_sec = 0; + rec->readTimestamp = FALSE; + rec->doNotSleep = FALSE; + + if (!rec->file) { + rfbClientLog("Could not open %s.\n",client->serverHost); + return FALSE; + } + setbuf(rec->file,0); + fread(buffer,1,strlen(magic),rec->file); + if (strncmp(buffer,magic,strlen(magic))) { + rfbClientLog("File %s was not recorded by vncrec.\n",client->serverHost); + fclose(rec->file); + return FALSE; + } + client->sock = 0; + return TRUE; + } + if (!StringToIPAddr(hostname, &host)) { rfbClientLog("Couldn't convert '%s' to host address\n", hostname); return FALSE; @@ -289,25 +315,28 @@ InitialiseRFBConnection(rfbClient* client) case rfbVncAuth: if (!ReadFromRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE; - if (client->GetPassword) - passwd = client->GetPassword(client); + if (client->serverPort!=-1) { /* if not playing a vncrec file */ + if (client->GetPassword) + passwd = client->GetPassword(client); - if ((!passwd) || (strlen(passwd) == 0)) { - rfbClientLog("Reading password failed\n"); - return FALSE; - } - if (strlen(passwd) > 8) { - passwd[8] = '\0'; - } + if ((!passwd) || (strlen(passwd) == 0)) { + rfbClientLog("Reading password failed\n"); + return FALSE; + } + if (strlen(passwd) > 8) { + passwd[8] = '\0'; + } - rfbEncryptBytes(challenge, passwd); + rfbEncryptBytes(challenge, passwd); - /* Lose the password from memory */ - for (i = strlen(passwd); i >= 0; i--) { - passwd[i] = '\0'; - } + /* Lose the password from memory */ + for (i = strlen(passwd); i >= 0; i--) { + passwd[i] = '\0'; + } + free(passwd); - if (!WriteToRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE; + if (!WriteToRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE; + } if (!ReadFromRFBServer(client, (char *)&authResult, 4)) return FALSE; @@ -638,6 +667,8 @@ HandleRFBServerMessage(rfbClient* client) { rfbServerToClientMsg msg; + if (client->serverPort==-1) + client->vncRec->readTimestamp = TRUE; if (!ReadFromRFBServer(client, (char *)&msg, 1)) return FALSE; diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c index a1e13b2..61298d4 100644 --- a/libvncclient/sockets.c +++ b/libvncclient/sockets.c @@ -58,12 +58,43 @@ static int buffered = 0; rfbBool ReadFromRFBServer(rfbClient* client, char *out, unsigned int n) { -//#define DEBUG_READ_EXACT +#undef DEBUG_READ_EXACT #ifdef DEBUG_READ_EXACT char* oout=out; int nn=n; rfbClientLog("ReadFromRFBServer %d bytes\n",n); #endif + if (client->serverPort==-1) { + /* vncrec playing */ + rfbVNCRec* rec = client->vncRec; + struct timeval tv; + + if (rec->readTimestamp) { + rec->readTimestamp = FALSE; + if (!fread(&tv,sizeof(struct timeval),1,rec->file)) + return FALSE; + + tv.tv_sec = rfbClientSwap32IfLE (tv.tv_sec); + tv.tv_usec = rfbClientSwap32IfLE (tv.tv_usec); + + if (rec->tv.tv_sec!=0 && !rec->doNotSleep) { + struct timeval diff; + diff.tv_sec = tv.tv_sec - rec->tv.tv_sec; + diff.tv_usec = tv.tv_usec - rec->tv.tv_usec; + if(diff.tv_usec<0) { + diff.tv_sec--; + diff.tv_usec+=1000000; + } + sleep (diff.tv_sec); + usleep (diff.tv_usec); + } + + rec->tv=tv; + } + + return (fread(out,1,n,rec->file)<0?FALSE:TRUE); + } + if (n <= buffered) { memcpy(out, bufoutptr, n); bufoutptr += n; @@ -161,6 +192,9 @@ WriteToRFBServer(rfbClient* client, char *buf, int n) int i = 0; int j; + if (client->serverPort==-1) + return TRUE; /* vncrec playing */ + while (i < n) { j = write(client->sock, buf + i, (n - i)); if (j <= 0) { @@ -445,6 +479,10 @@ int WaitForMessage(rfbClient* client,unsigned int usecs) struct timeval timeout; int num; + if (client->serverPort==-1) + /* playing back vncrec file */ + return 1; + timeout.tv_sec=(usecs/1000000); timeout.tv_usec=(usecs%1000000); diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c index 6a58e78..712f52e 100644 --- a/libvncclient/vncviewer.c +++ b/libvncclient/vncviewer.c @@ -34,7 +34,23 @@ static rfbBool DummyPoint(rfbClient* client, int x, int y) { static void DummyRect(rfbClient* client, int x, int y, int w, int h) { } static char* NoPassword(rfbClient* client) { - return ""; + return strdup(""); +} +#include +#include +static char* ReadPassword(rfbClient* client) { + int i=8; + char* p=malloc(9); + struct termios save,noecho; + p[0]=0; + if(tcgetattr(fileno(stdin),&save)!=0) return p; + noecho=save; noecho.c_lflag &= ~ECHO; + if(tcsetattr(fileno(stdin),TCSAFLUSH,&noecho)!=0) return p; + fprintf(stderr,"Password: "); + getline(&p,&i,stdin); + if(i>0 && p[i-2]=='\n') p[i-2]=0; + tcsetattr(fileno(stdin),TCSAFLUSH,&save); + return p; } static rfbBool MallocFrameBuffer(rfbClient* client) { if(client->frameBuffer) @@ -107,7 +123,7 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->SoftCursorLockArea = DummyRect; client->SoftCursorUnlockScreen = Dummy; client->GotFrameBufferUpdate = DummyRect; - client->GetPassword = NoPassword; + client->GetPassword = ReadPassword; client->MallocFrameBuffer = MallocFrameBuffer; client->Bell = Dummy; @@ -143,15 +159,22 @@ static rfbBool rfbInitConnection(rfbClient* client) } rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) { - int i; + int i,j; if(client->programName==0) client->programName=argv[0]; for (i = 1; i < *argc; i++) { + j = i; if (strcmp(argv[i], "-listen") == 0) { listenForIncomingConnections(client); break; + } else if (strcmp(argv[i], "-play") == 0) { + client->serverPort = -1; + j++; + } else if (i+1<*argc && strcmp(argv[i], "-encodings") == 0) { + client->appData.encodingsString = argv[i+1]; + j+=2; } else { char* colon=strchr(argv[i],':'); @@ -159,9 +182,15 @@ rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) { if(colon) { *colon=0; client->serverPort=atoi(colon+1); - } else - client->serverPort=0; - client->serverPort+=5900; + } + if(client->serverPort>=0 && client->serverPort<5900) + client->serverPort+=5900; + } + /* purge arguments */ + if (j>i) { + *argc-=j-i; + memmove(argv+i,argv+j,(*argc-i)*sizeof(char*)); + i--; } }