The "xc" tree merged with VNC 4.1.1 code.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@526 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/xc/programs/Xserver/vnc/vncExtInit.cc b/xc/programs/Xserver/vnc/vncExtInit.cc
index ccaf5b8..9cf9d21 100644
--- a/xc/programs/Xserver/vnc/vncExtInit.cc
+++ b/xc/programs/Xserver/vnc/vncExtInit.cc
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -81,6 +81,11 @@
 static char* clientCutText = 0;
 static int clientCutTextLen = 0;
 
+static XserverDesktop* queryConnectDesktop = 0;
+static void* queryConnectId = 0;
+static int queryConnectTimeout = 0;
+static OsTimerPtr queryConnectTimer = 0;
+
 static struct VncInputSelect* vncInputSelectHead = 0;
 struct VncInputSelect {
   VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m)
@@ -102,9 +107,8 @@
 static char* vncPasswdFile = 0;
 int vncInetdSock = -1;
 
-rfb::VncAuthPasswdFileParameter vncAuthPasswdFile;
 rfb::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
-                            &vncAuthPasswdFile.param);
+                            &SSecurityFactoryStandard::vncAuthPasswdFile);
 rfb::StringParameter httpDir("httpd",
                              "Directory containing files to serve via HTTP",
                              "");
@@ -315,6 +319,74 @@
   }
 }
 
+
+static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
+                                        CARD32 now, pointer arg)
+{
+  if (queryConnectTimeout)
+    queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
+  // Re-notify clients, causing them to discover that we're done
+  vncQueryConnect(queryConnectDesktop, queryConnectId);
+  return 0;
+}
+
+void vncQueryConnect(XserverDesktop* desktop, void* opaqueId)
+{
+  // Only one query can be processed at any one time
+  if (queryConnectTimeout && ((desktop != queryConnectDesktop) ||
+                              (opaqueId != queryConnectId))) {
+    desktop->approveConnection(opaqueId, false,
+                               "Another connection is currently being queried.");
+    return;
+  }
+
+  // Get the query timeout.  If it's zero, there is no query.
+  queryConnectTimeout = desktop->getQueryTimeout(opaqueId);
+  queryConnectId = queryConnectTimeout ? opaqueId : 0;
+  queryConnectDesktop = queryConnectTimeout ? desktop : 0;
+
+  // Notify clients
+  bool notified = false;
+  xVncExtQueryConnectNotifyEvent ev;
+  ev.type = vncEventBase + VncExtQueryConnectNotify;
+  for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+    if (cur->mask & VncExtQueryConnectMask) {
+      ev.sequenceNumber = cur->client->sequence;
+      ev.window = cur->window;
+      if (cur->client->swapped) {
+        int n;
+        swaps(&ev.sequenceNumber, n);
+        swapl(&ev.window, n);
+      }
+      WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
+                    (char *)&ev);
+      notified = true;
+    }
+  }
+
+  // If we're being asked to query a connection (rather than to cancel
+  //   a query), and haven't been able to notify clients then reject it.
+  if (queryConnectTimeout && !notified) {
+    queryConnectTimeout = 0;
+    queryConnectId = 0;
+    queryConnectDesktop = 0;
+    desktop->approveConnection(opaqueId, false,
+                               "Unable to query the local user to accept the connection.");
+    return;
+  }    
+
+  // Set a timer so that if no-one ever responds, we will eventually 
+  //   reject the connection
+  //   NB: We don't set a timer if sock is null, since that indicates
+  //       that pending queries should be cancelled.
+  if (queryConnectDesktop)
+    queryConnectTimer = TimerSet(queryConnectTimer, 0,
+                                 queryConnectTimeout*2000,
+                                 queryConnectTimerCallback, 0);
+  else
+    TimerCancel(queryConnectTimer);
+}
+
 static void SendSelectionChangeEvent(Atom selection)
 {
   xVncExtSelectionChangeNotifyEvent ev;
@@ -469,14 +541,12 @@
 
   int nParams = 0;
   int len = 0;
-  rfb::VoidParameter* current = rfb::Configuration::head;
-  while (current) {
-    int l = strlen(current->getName());
+  for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+    int l = strlen(i.param->getName());
     if (l <= 255) {
       nParams++;
       len += l + 1;
     }
-    current = current->_next;
   }
   rep.length = (len + 3) >> 2;
   rep.nParams = nParams;
@@ -488,15 +558,13 @@
   WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
   rdr::U8* data = new rdr::U8[len];
   rdr::U8* ptr = data;
-  current = rfb::Configuration::head;
-  while (current) {
-    int l = strlen(current->getName());
+  for (ParameterIterator i(Configuration::global()); i.param; i.next()) {
+    int l = strlen(i.param->getName());
     if (l <= 255) {
       *ptr++ = l;
-      memcpy(ptr, current->getName(), l);
+      memcpy(ptr, i.param->getName(), l);
       ptr += l;
     }
-    current = current->_next;
   }
   WriteToClient(client, len, (char*)data);
   delete [] data;
@@ -662,6 +730,82 @@
   return ProcVncExtConnect(client);
 }
 
+
+static int ProcVncExtGetQueryConnect(ClientPtr client)
+{
+  REQUEST(xVncExtGetQueryConnectReq);
+  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+
+  const char *qcAddress=0, *qcUsername=0;
+  int qcTimeout;
+  if (queryConnectDesktop)
+    qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId,
+                                                     &qcAddress, &qcUsername);
+  else
+    qcTimeout = 0;
+
+  xVncExtGetQueryConnectReply rep;
+  int n;
+  rep.type = X_Reply;
+  rep.sequenceNumber = client->sequence;
+  rep.timeout = qcTimeout;
+  rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
+  rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
+  rep.opaqueId = (CARD32)queryConnectId;
+  rep.length = (rep.userLen + rep.addrLen + 3) >> 2;
+  if (client->swapped) {
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.userLen, n);
+    swapl(&rep.addrLen, n);
+    swapl(&rep.timeout, n);
+    swapl(&rep.opaqueId, n);
+  }
+  WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
+  if (qcTimeout)
+    WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
+  if (qcTimeout)
+    WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
+  return (client->noClientException);
+}
+
+static int SProcVncExtGetQueryConnect(ClientPtr client)
+{
+  register char n;
+  REQUEST(xVncExtGetQueryConnectReq);
+  swaps(&stuff->length, n);
+  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+  return ProcVncExtGetQueryConnect(client);
+}
+
+
+static int ProcVncExtApproveConnect(ClientPtr client)
+{
+  REQUEST(xVncExtApproveConnectReq);
+  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+  if (queryConnectId == (void*)stuff->opaqueId) {
+    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+      if (desktop[scr]) {
+        desktop[scr]->approveConnection(queryConnectId, stuff->approve,
+                                        "Connection rejected by local user");
+      }
+    }
+    // Inform other clients of the event and tidy up
+    vncQueryConnect(queryConnectDesktop, queryConnectId);
+  }
+  return (client->noClientException);
+}
+
+static int SProcVncExtApproveConnect(ClientPtr client)
+{
+  register char n;
+  REQUEST(xVncExtApproveConnectReq);
+  swaps(&stuff->length, n);
+  swapl(&stuff->opaqueId, n);
+  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+  return ProcVncExtApproveConnect(client);
+}
+
+
 static int ProcVncExtDispatch(ClientPtr client)
 {
   REQUEST(xReq);
@@ -682,6 +826,10 @@
     return ProcVncExtSelectInput(client);
   case X_VncExtConnect:
     return ProcVncExtConnect(client);
+  case X_VncExtGetQueryConnect:
+    return ProcVncExtGetQueryConnect(client);
+  case X_VncExtApproveConnect:
+    return ProcVncExtApproveConnect(client);
   default:
     return BadRequest;
   }
@@ -707,6 +855,10 @@
     return SProcVncExtSelectInput(client);
   case X_VncExtConnect:
     return SProcVncExtConnect(client);
+  case X_VncExtGetQueryConnect:
+    return SProcVncExtGetQueryConnect(client);
+  case X_VncExtApproveConnect:
+    return SProcVncExtApproveConnect(client);
   default:
     return BadRequest;
   }