reimplement confirmation on exit if there are downloads in progress
[kdenetwork.git] / krfb / krfbserver.cpp
blob7a29a6d53e9e4bb371f31fac3e5d35bd7275a607
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; version 2
8 of the License.
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 <KStaticDeleter>
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;
130 static KStaticDeleter<KrfbServer> sd;
131 KrfbServer * KrfbServer::_self = 0;
132 KrfbServer * KrfbServer::self() {
133 if (!_self) sd.setObject(_self, new KrfbServer);
134 return _self;
138 KrfbServer::KrfbServer()
139 :d(new KrfbServerP)
141 kDebug() << "starting " << endl;
142 d->running = true;
143 d->fb = FrameBuffer::getFrameBuffer(QApplication::desktop()->winId(), this);
144 QTimer::singleShot(0, this, SLOT(startListening()));
145 connect(InvitationManager::self(), SIGNAL(invitationNumChanged(int)),SLOT(updatePassword()));
149 KrfbServer::~KrfbServer()
151 delete d;
155 void KrfbServer::startListening()
157 rfbScreenInfoPtr screen;
159 int port = KrfbConfig::port();
161 int w = d->fb->width();
162 int h = d->fb->height();
163 int depth = d->fb->depth();
165 rfbLogEnable(0);
166 screen = rfbGetScreen(0, 0, w, h, 8, 3,depth / 8);
167 screen->paddedWidthInBytes = d->fb->paddedWidth();
169 d->fb->getServerFormat(screen->serverFormat);
171 screen->frameBuffer = d->fb->data();
172 d->screen = screen;
173 screen->autoPort = 0;
174 screen->port = port;
176 // server hooks
177 screen->newClientHook = newClientHook;
179 screen->kbdAddEvent = keyboardHook;
180 screen->ptrAddEvent = pointerHook;
181 screen->newClientHook = newClientHook;
182 screen->passwordCheck = passwordCheck;
183 screen->setXCutText = clipboardHook;
185 screen->desktopName = i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()).toLatin1().data();
187 if (!myCursor) {
188 myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
190 screen->cursor = myCursor;
192 // configure passwords and desktop control here
193 updateSettings();
195 rfbInitServer(screen);
196 if (!rfbIsActive(screen)) {
197 KMessageBox::error(0,"krfb","Address already in use");
198 disconnectAndQuit();
201 if (KrfbConfig::publishService()) {
202 DNSSD::PublicService *service = new DNSSD::PublicService(i18n("%1@%2 (shared desktop)", KUser().loginName(), QHostInfo::localHostName()),"_rfb._tcp",port);
203 service->publishAsync();
206 while (d->running) {
207 foreach(QRect r, d->fb->modifiedTiles()) {
208 rfbMarkRectAsModified(screen, r.x(), r.y(), r.right(), r.bottom());
210 rfbProcessEvents(screen, 100);
211 qApp->processEvents();
213 rfbShutdownServer(screen, true);
214 emit quitApp();
218 void KrfbServer::enableDesktopControl(bool enable)
220 foreach (QPointer<ConnectionController> ptr, d->controllers) {
221 if (ptr) {
222 ptr->setControlEnabled(enable);
227 void KrfbServer::disconnectAndQuit()
229 d->running = false;
232 enum rfbNewClientAction KrfbServer::handleNewClient(struct _rfbClientRec * cl)
234 ConnectionController *cc = new ConnectionController(cl, this);
235 if (d->numClients == 0) {
236 d->fb->startMonitor();
237 d->numClients++;
240 d->controllers.append(cc);
241 cc->setControlEnabled(KrfbConfig::allowDesktopControl());
243 connect(cc, SIGNAL(sessionEstablished(QString)), SIGNAL(sessionEstablished(QString)));
244 connect(cc, SIGNAL(clientDisconnected(ConnectionController *)),SLOT(clientDisconnected(ConnectionController *)));
246 return cc->handleNewClient();
249 void KrfbServer::updateSettings()
251 enableDesktopControl(KrfbConfig::allowDesktopControl());
252 updatePassword();
255 void KrfbServer::updatePassword()
258 if (!d->screen) return;
259 QString pw = KrfbConfig::uninvitedConnectionPassword();
260 kDebug() << "password: " << pw << " allow " <<
261 KrfbConfig::allowUninvitedConnections() <<
262 " invitations " << InvitationManager::self()->activeInvitations() << endl;
264 if (pw.isEmpty() && InvitationManager::self()->activeInvitations() == 0) {
265 kDebug() << "no password from now on" << endl;
266 d->screen->authPasswdData = (void *)0;
267 } else {
268 kDebug() << "Ask for password to accept connections" << endl;
269 d->screen->authPasswdData = (void *)1;
273 bool KrfbServer::checkX11Capabilities() {
274 int bp1, bp2, majorv, minorv;
275 Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
276 &majorv, &minorv);
277 if ((!r) || (((majorv*1000)+minorv) < 2002)) {
278 KMessageBox::error(0,
279 i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
280 i18n("Desktop Sharing Error"));
281 return false;
284 return true;
287 void KrfbServer::clientDisconnected(ConnectionController *cc)
289 kDebug() << "clients--: " << d->numClients << endl;
290 d->numClients--;
291 if (d->numClients == 0) {
292 d->fb->stopMonitor();
294 disconnect(cc, SIGNAL(clientDisconnected(ConnectionController)),this, SLOT(clientDisconnected(ConnectionController)));