00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "krfbserver.h"
00013 #include "krfbserver.moc"
00014
00015 #include <QTcpServer>
00016 #include <QTcpSocket>
00017 #include <QTimer>
00018 #include <QHostInfo>
00019 #include <QApplication>
00020 #include <QDesktopWidget>
00021 #include <QPointer>
00022
00023 #include <KGlobal>
00024 #include <KUser>
00025 #include <KLocale>
00026 #include <KDebug>
00027 #include <KMessageBox>
00028 #include <dnssd/publicservice.h>
00029
00030 #include "connectioncontroller.h"
00031 #include "framebuffer.h"
00032 #include "krfbconfig.h"
00033 #include "invitationmanager.h"
00034
00035 #include <X11/Xutil.h>
00036 #include <X11/extensions/XTest.h>
00037
00038
00039 static const char* cur=
00040 " "
00041 " x "
00042 " xx "
00043 " xxx "
00044 " xxxx "
00045 " xxxxx "
00046 " xxxxxx "
00047 " xxxxxxx "
00048 " xxxxxxxx "
00049 " xxxxxxxxx "
00050 " xxxxxxxxxx "
00051 " xxxxx "
00052 " xx xxx "
00053 " x xxx "
00054 " xxx "
00055 " xxx "
00056 " xxx "
00057 " xxx "
00058 " ";
00059
00060 static const char* mask=
00061 "xx "
00062 "xxx "
00063 "xxxx "
00064 "xxxxx "
00065 "xxxxxx "
00066 "xxxxxxx "
00067 "xxxxxxxx "
00068 "xxxxxxxxx "
00069 "xxxxxxxxxx "
00070 "xxxxxxxxxxx "
00071 "xxxxxxxxxxxx "
00072 "xxxxxxxxxx "
00073 "xxxxxxxx "
00074 "xxxxxxxx "
00075 "xx xxxxx "
00076 " xxxxx "
00077 " xxxxx "
00078 " xxxxx "
00079 " xxx ";
00080
00081 static rfbCursorPtr myCursor;
00082
00083
00084 static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
00085 {
00086 KrfbServer *server = KrfbServer::self();
00087 return server->handleNewClient(cl);
00088 }
00089
00090 static rfbBool passwordCheck(rfbClientPtr cl,
00091 const char* encryptedPassword,
00092 int len)
00093 {
00094 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
00095 return cc->handleCheckPassword(cl, encryptedPassword, len);
00096 }
00097
00098 static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
00099 {
00100 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
00101 cc->handleKeyEvent(down ? true : false, keySym);
00102 }
00103
00104 static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
00105 {
00106 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
00107 cc->handlePointerEvent(bm, x, y);
00108 }
00109
00110 static void clipboardHook(char* str,int len, rfbClientPtr cl)
00111 {
00112 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
00113 cc->clipboardToServer(QString::fromUtf8(str, len));
00114 }
00115
00116
00117 class KrfbServer::KrfbServerP {
00118
00119 public:
00120 KrfbServerP() : fb(0), screen(0), numClients(0) {};
00121
00122 FrameBuffer *fb;
00123 QList< QPointer<ConnectionController> > controllers;
00124 rfbScreenInfoPtr screen;
00125 bool running;
00126 int numClients;
00127 QByteArray desktopName;
00128 };
00129
00130 class KrfbServerPrivate
00131 {
00132 public:
00133 KrfbServer instance;
00134 };
00135
00136 K_GLOBAL_STATIC(KrfbServerPrivate, krfbServerPrivate)
00137
00138 KrfbServer * KrfbServer::self() {
00139 return &krfbServerPrivate->instance;
00140 }
00141
00142
00143 KrfbServer::KrfbServer()
00144 :d(new KrfbServerP)
00145 {
00146 kDebug() << "starting ";
00147 d->running = true;
00148 d->fb = FrameBuffer::getFrameBuffer(QApplication::desktop()->winId(), this);
00149 QTimer::singleShot(0, this, SLOT(startListening()));
00150 connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
00151 }
00152
00153 KrfbServer::~KrfbServer()
00154 {
00155 delete d;
00156 }
00157
00158
00159 void KrfbServer::startListening()
00160 {
00161 rfbScreenInfoPtr screen;
00162
00163 int port = KrfbConfig::port();
00164
00165 int w = d->fb->width();
00166 int h = d->fb->height();
00167 int depth = d->fb->depth();
00168
00169 rfbLogEnable(0);
00170 screen = rfbGetScreen(0, 0, w, h, 8, 3,depth / 8);
00171 screen->paddedWidthInBytes = d->fb->paddedWidth();
00172
00173 d->fb->getServerFormat(screen->serverFormat);
00174
00175 screen->frameBuffer = d->fb->data();
00176 d->screen = screen;
00177 screen->autoPort = 0;
00178 screen->port = port;
00179
00180
00181 screen->newClientHook = newClientHook;
00182
00183 screen->kbdAddEvent = keyboardHook;
00184 screen->ptrAddEvent = pointerHook;
00185 screen->newClientHook = newClientHook;
00186 screen->passwordCheck = passwordCheck;
00187 screen->setXCutText = clipboardHook;
00188
00189 d->desktopName = i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1();
00190 screen->desktopName = d->desktopName.constData();
00191
00192 if (!myCursor) {
00193 myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
00194 }
00195 screen->cursor = myCursor;
00196
00197
00198 updateSettings();
00199
00200 rfbInitServer(screen);
00201 if (!rfbIsActive(screen)) {
00202 KMessageBox::error(0,"krfb","Address already in use");
00203 disconnectAndQuit();
00204 };
00205
00206 if (KrfbConfig::publishService()) {
00207 DNSSD::PublicService *service = new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port);
00208 service->publishAsync();
00209 }
00210
00211 while (d->running) {
00212 foreach(QRect r, d->fb->modifiedTiles()) {
00213 rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
00214 }
00215 rfbProcessEvents(screen, 100);
00216 qApp->processEvents();
00217 }
00218 rfbShutdownServer(screen, true);
00219
00220 delete d->fb;
00221 d->fb = 0;
00222
00223 emit quitApp();
00224 }
00225
00226
00227 void KrfbServer::enableDesktopControl(bool enable)
00228 {
00229 foreach (QPointer<ConnectionController> ptr, d->controllers) {
00230 if (ptr) {
00231 ptr->setControlEnabled(enable);
00232 }
00233 }
00234 }
00235
00236 void KrfbServer::disconnectAndQuit()
00237 {
00238 d->running = false;
00239 }
00240
00241 enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
00242 {
00243 ConnectionController *cc = new ConnectionController(cl, this);
00244 if (d->numClients++ == 0)
00245 d->fb->startMonitor();
00246
00247 d->controllers.append(cc);
00248 cc->setControlEnabled(KrfbConfig::allowDesktopControl());
00249
00250 connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
00251 connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
00252
00253 return cc->handleNewClient();
00254 }
00255
00256 void KrfbServer::updateSettings()
00257 {
00258 enableDesktopControl(KrfbConfig::allowDesktopControl());
00259 updatePassword();
00260 }
00261
00262 void KrfbServer::updatePassword()
00263 {
00264
00265 if (!d->screen) return;
00266 QString pw = KrfbConfig::uninvitedConnectionPassword();
00267 kDebug() << "password: " << pw << " allow " <<
00268 KrfbConfig::allowUninvitedConnections() <<
00269 " invitations " << InvitationManager::self()->activeInvitations() << endl;
00270
00271 if (pw.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
00272 kDebug() << "no password from now on";
00273 d->screen->authPasswdData = (void *)0;
00274 } else {
00275 kDebug() << "Ask for password to accept connections";
00276 d->screen->authPasswdData = (void *)1;
00277 }
00278 }
00279
00280 bool KrfbServer::checkX11Capabilities() {
00281 int bp1, bp2, majorv, minorv;
00282 Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
00283 &majorv, &minorv);
00284 if ((!r) || (((majorv*1000)+minorv) < 2002)) {
00285 KMessageBox::error(0,
00286 i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
00287 i18n("Desktop Sharing Error"));
00288 return false;
00289 }
00290
00291 return true;
00292 }
00293
00294 void KrfbServer::clientDisconnected(ConnectionController *cc)
00295 {
00296 kDebug() << "clients--: " << d->numClients;
00297 if (!--d->numClients) {
00298 d->fb->stopMonitor();
00299 }
00300 disconnect(cc, SIGNAL(clientDisconnected(ConnectionController)),this, SLOT(clientDisconnected(ConnectionController)));
00301 }
00302
00303