* do not add a KStandardAction manually to actionCollection()
[kdenetwork.git] / krfb / krfbserver.cpp
blobdfb0cf972b2f72d6bf63fe5f344359aca3ae936d
1 /* This file is part of the KDE project
2 Copyright (C) 2007 Alessandro Praduroux <pradu@pradu.it>
3 (C) 2001-2003 by Tim Jansen <tim@tjansen.de>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9 */
12 #include "krfbserver.h"
13 #include "krfbserver.moc"
15 #include <QTcpServer>
16 #include <QTcpSocket>
17 #include <QTimer>
18 #include <QHostInfo>
19 #include <QApplication>
20 #include <QDesktopWidget>
21 #include <QPointer>
23 #include <KGlobal>
24 #include <KUser>
25 #include <KLocale>
26 #include <KDebug>
27 #include <KMessageBox>
28 #include <dnssd/publicservice.h>
30 #include "connectioncontroller.h"
31 #include "framebuffer.h"
32 #include "krfbconfig.h"
33 #include "invitationmanager.h"
35 #include <X11/Xutil.h>
36 #include <X11/extensions/XTest.h>
39 static const char* cur=
40 " "
41 " x "
42 " xx "
43 " xxx "
44 " xxxx "
45 " xxxxx "
46 " xxxxxx "
47 " xxxxxxx "
48 " xxxxxxxx "
49 " xxxxxxxxx "
50 " xxxxxxxxxx "
51 " xxxxx "
52 " xx xxx "
53 " x xxx "
54 " xxx "
55 " xxx "
56 " xxx "
57 " xxx "
58 " ";
60 static const char* mask=
61 "xx "
62 "xxx "
63 "xxxx "
64 "xxxxx "
65 "xxxxxx "
66 "xxxxxxx "
67 "xxxxxxxx "
68 "xxxxxxxxx "
69 "xxxxxxxxxx "
70 "xxxxxxxxxxx "
71 "xxxxxxxxxxxx "
72 "xxxxxxxxxx "
73 "xxxxxxxx "
74 "xxxxxxxx "
75 "xx xxxxx "
76 " xxxxx "
77 " xxxxx "
78 " xxxxx "
79 " xxx ";
81 static rfbCursorPtr myCursor;
84 static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
86 KrfbServer *server = KrfbServer::self();
87 return server->handleNewClient(cl);
90 static rfbBool passwordCheck(rfbClientPtr cl,
91 const char* encryptedPassword,
92 int len)
94 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
95 return cc->handleCheckPassword(cl, encryptedPassword, len);
98 static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl)
100 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
101 cc->handleKeyEvent(down ? true : false, keySym);
104 static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
106 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
107 cc->handlePointerEvent(bm, x, y);
110 static void clipboardHook(char* str,int len, rfbClientPtr cl)
112 ConnectionController *cc = static_cast<ConnectionController *>(cl->clientData);
113 cc->clipboardToServer(QString::fromUtf8(str, len));
117 class KrfbServer::KrfbServerP {
119 public:
120 KrfbServerP() : fb(0), screen(0), numClients(0) {};
122 FrameBuffer *fb;
123 QList< QPointer<ConnectionController> > controllers;
124 rfbScreenInfoPtr screen;
125 bool running;
126 int numClients;
127 QByteArray desktopName;
130 class KrfbServerPrivate
132 public:
133 KrfbServer instance;
136 K_GLOBAL_STATIC(KrfbServerPrivate, krfbServerPrivate)
138 KrfbServer * KrfbServer::self() {
139 return &krfbServerPrivate->instance;
143 KrfbServer::KrfbServer()
144 :d(new KrfbServerP)
146 kDebug() << "starting ";
147 d->running = true;
148 d->fb = FrameBuffer::getFrameBuffer(QApplication::desktop()->winId(), this);
149 QTimer::singleShot(0, this, SLOT(startListening()));
150 connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
153 KrfbServer::~KrfbServer()
155 delete d;
159 void KrfbServer::startListening()
161 rfbScreenInfoPtr screen;
163 int port = KrfbConfig::port();
165 int w = d->fb->width();
166 int h = d->fb->height();
167 int depth = d->fb->depth();
169 rfbLogEnable(0);
170 screen = rfbGetScreen(0, 0, w, h, 8, 3,depth / 8);
171 screen->paddedWidthInBytes = d->fb->paddedWidth();
173 d->fb->getServerFormat(screen->serverFormat);
175 screen->frameBuffer = d->fb->data();
176 d->screen = screen;
177 screen->autoPort = 0;
178 screen->port = port;
180 // server hooks
181 screen->newClientHook = newClientHook;
183 screen->kbdAddEvent = keyboardHook;
184 screen->ptrAddEvent = pointerHook;
185 screen->newClientHook = newClientHook;
186 screen->passwordCheck = passwordCheck;
187 screen->setXCutText = clipboardHook;
189 d->desktopName = i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1();
190 screen->desktopName = d->desktopName.constData();
192 if (!myCursor) {
193 myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
195 screen->cursor = myCursor;
197 // configure passwords and desktop control here
198 updateSettings();
200 rfbInitServer(screen);
201 if (!rfbIsActive(screen)) {
202 KMessageBox::error(0,i18n("Address already in use"),"krfb");
203 disconnectAndQuit();
206 if (KrfbConfig::publishService()) {
207 DNSSD::PublicService *service = new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port);
208 service->publishAsync();
211 while (d->running) {
212 foreach(const QRect &r, d->fb->modifiedTiles()) {
213 rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
215 rfbProcessEvents(screen, 100);
216 qApp->processEvents();
218 rfbShutdownServer(screen, true);
219 // framebuffer has to be deleted before X11 connection goes down
220 delete d->fb;
221 d->fb = 0;
223 emit quitApp();
227 void KrfbServer::enableDesktopControl(bool enable)
229 foreach (QPointer<ConnectionController> ptr, d->controllers) {
230 if (ptr) {
231 ptr->setControlEnabled(enable);
236 void KrfbServer::disconnectAndQuit()
238 d->running = false;
241 enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
243 ConnectionController *cc = new ConnectionController(cl, this);
244 if (d->numClients++ == 0)
245 d->fb->startMonitor();
247 d->controllers.append(cc);
248 cc->setControlEnabled(KrfbConfig::allowDesktopControl());
250 connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
251 connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
253 return cc->handleNewClient();
256 void KrfbServer::updateSettings()
258 enableDesktopControl(KrfbConfig::allowDesktopControl());
259 updatePassword();
262 void KrfbServer::updatePassword()
265 if (!d->screen) return;
266 QString pw = KrfbConfig::uninvitedConnectionPassword();
267 kDebug() << "password: " << pw << " allow " <<
268 KrfbConfig::allowUninvitedConnections() <<
269 " invitations " << InvitationManager::self()->activeInvitations() << endl;
271 if (pw.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
272 kDebug() << "no password from now on";
273 d->screen->authPasswdData = (void *)0;
274 } else {
275 kDebug() << "Ask for password to accept connections";
276 d->screen->authPasswdData = (void *)1;
280 bool KrfbServer::checkX11Capabilities() {
281 int bp1, bp2, majorv, minorv;
282 Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
283 &majorv, &minorv);
284 if ((!r) || (((majorv*1000)+minorv) < 2002)) {
285 KMessageBox::error(0,
286 i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
287 i18n("Desktop Sharing Error"));
288 return false;
291 return true;
294 void KrfbServer::clientDisconnected(ConnectionController *cc)
296 kDebug() << "clients--: " << d->numClients;
297 if (!--d->numClients) {
298 d->fb->stopMonitor();
300 disconnect(cc, SIGNAL(clientDisconnected(ConnectionController)),this, SLOT(clientDisconnected(ConnectionController)));