blob: 0d95180cba26ca4771ca51431a4efd60eeb653f8 [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <windows.h>
20#include <winsock2.h>
21#include <vncviewer/UserPasswdDialog.h>
22#include <vncviewer/CConn.h>
23#include <vncviewer/CConnThread.h>
24#include <vncviewer/resource.h>
25#include <rfb/encodings.h>
26#include <rfb/secTypes.h>
27#include <rfb/CSecurityNone.h>
28#include <rfb/CSecurityVncAuth.h>
29#include <rfb/CMsgWriter.h>
30#include <rfb/Configuration.h>
31#include <rfb/LogWriter.h>
32#include <rfb_win32/AboutDialog.h>
33
34using namespace rfb;
35using namespace rfb::win32;
36using namespace rdr;
37
38// - Statics & consts
39
40static LogWriter vlog("CConn");
41
42
43const int IDM_FULLSCREEN = ID_FULLSCREEN;
44const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
45const int IDM_SEND_CAD = ID_SEND_CAD;
46const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
47const int IDM_ABOUT = ID_ABOUT;
48const int IDM_OPTIONS = ID_OPTIONS;
49const int IDM_INFO = ID_INFO;
50const int IDM_NEWCONN = ID_NEW_CONNECTION;
51const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
52const int IDM_CTRL_KEY = ID_CTRL_KEY;
53const int IDM_ALT_KEY = ID_ALT_KEY;
54const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
55const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
george824f72ab32006-09-10 05:13:45 +000056const int IDM_ZOOM_IN = ID_ZOOM_IN;
57const int IDM_ZOOM_OUT = ID_ZOOM_OUT;
58const int IDM_ACTUAL_SIZE = ID_ACTUAL_SIZE;
59const int IDM_AUTO_SIZE = ID_AUTO_SIZE;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000060
61
62static IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
63 "pixel data - a debugging feature", 0);
64
george82b6d87aa2006-09-11 07:00:59 +000065const int scaleValues[9] = {10, 25, 50, 75, 90, 100, 125, 150, 200};
66const int scaleCount = 9;
67
Constantin Kaplinsky729598c2006-05-25 05:12:25 +000068
69//
70// -=- CConn implementation
71//
72
73RegKey CConn::userConfigKey;
74
75
76CConn::CConn()
77 : window(0), sock(0), sockEvent(CreateEvent(0, TRUE, FALSE, 0)), requestUpdate(false),
78 sameMachine(false), encodingChange(false), formatChange(false),
79 reverseConnection(false), lastUsedEncoding_(encodingRaw), isClosed_(false) {
80}
81
82CConn::~CConn() {
83 delete window;
84}
85
86bool CConn::initialise(network::Socket* s, bool reverse) {
87 // Set the server's name for MRU purposes
88 CharArray endpoint(s->getPeerEndpoint());
89 setServerName(endpoint.buf);
90 if (!options.host.buf)
91 options.setHost(endpoint.buf);
92
93 // Initialise the underlying CConnection
94 setStreams(&s->inStream(), &s->outStream());
95
96 // Enable processing of window messages while blocked on I/O
97 s->inStream().setBlockCallback(this);
98
99 // Initialise the viewer options
100 applyOptions(options);
101
102 // - Set which auth schemes we support, in order of preference
103 addSecType(secTypeVncAuth);
104 addSecType(secTypeNone);
105
106 // Start the RFB protocol
107 sock = s;
108 reverseConnection = reverse;
109 initialiseProtocol();
110
111 m_fileTransfer.initialize(&s->inStream(), &s->outStream());
112
113 return true;
114}
115
116
117void
118CConn::applyOptions(CConnOptions& opt) {
119 // - If any encoding-related settings have changed then we must
120 // notify the server of the new settings
121 encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
122 (options.useDesktopResize != opt.useDesktopResize) ||
123 (options.customCompressLevel != opt.customCompressLevel) ||
124 (options.compressLevel != opt.compressLevel) ||
125 (options.noJpeg != opt.noJpeg) ||
126 (options.qualityLevel != opt.qualityLevel) ||
127 (options.preferredEncoding != opt.preferredEncoding));
128
129 // - If the preferred pixel format has changed then notify the server
130 formatChange |= (options.fullColour != opt.fullColour);
131 if (!opt.fullColour)
132 formatChange |= (options.lowColourLevel != opt.lowColourLevel);
133
134 // - Save the new set of options
135 options = opt;
136
137 // - Set optional features in ConnParams
138 cp.supportsLocalCursor = options.useLocalCursor;
139 cp.supportsDesktopResize = options.useDesktopResize;
140 cp.customCompressLevel = options.customCompressLevel;
141 cp.compressLevel = options.compressLevel;
142 cp.noJpeg = options.noJpeg;
143 cp.qualityLevel = options.qualityLevel;
144
145 // - Configure connection sharing on/off
146 setShared(options.shared);
147
148 // - Whether to use protocol 3.3 for legacy compatibility
149 setProtocol3_3(options.protocol3_3);
150
151 // - Apply settings that affect the window, if it is visible
152 if (window) {
153 window->setMonitor(options.monitor.buf);
154 window->setFullscreen(options.fullScreen);
155 window->setEmulate3(options.emulate3);
156 window->setPointerEventInterval(options.pointerEventInterval);
157 window->setMenuKey(options.menuKey);
158 window->setDisableWinKeys(options.disableWinKeys);
159 window->setShowToolbar(options.showToolbar);
george82ffc14a62006-09-05 06:51:41 +0000160 if (options.autoScaling) {
161 window->setAutoScaling(true);
162 } else {
163 window->setAutoScaling(false);
164 window->setDesktopScale(options.scale);
165 }
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000166 if (!options.useLocalCursor)
167 window->setCursor(0, 0, Point(), 0, 0);
168 }
169}
170
171
172void
173CConn::displayChanged() {
174 // Display format has changed - recalculate the full-colour pixel format
175 calculateFullColourPF();
176}
177
178void
179CConn::paintCompleted() {
180 // A repaint message has just completed - request next update if necessary
181 requestNewUpdate();
182}
183
184bool
185CConn::sysCommand(WPARAM wParam, LPARAM lParam) {
186 // - If it's one of our (F8 Menu) messages
187 switch (wParam) {
188 case IDM_FULLSCREEN:
189 options.fullScreen = !window->isFullscreen();
190 window->setFullscreen(options.fullScreen);
191 return true;
george824f72ab32006-09-10 05:13:45 +0000192 case IDM_ZOOM_IN:
george824f72ab32006-09-10 05:13:45 +0000193 case IDM_ZOOM_OUT:
george82b6d87aa2006-09-11 07:00:59 +0000194 {
195 if (options.autoScaling) {
196 options.scale = window->getDesktopScale();
197 options.autoScaling = false;
198 window->setAutoScaling(false);
199 }
200 if (wParam == IDM_ZOOM_IN) {
201 for (int i = 0; i < scaleCount; i++)
202 if (options.scale < scaleValues[i]) {
203 options.scale = scaleValues[i];
204 break;
205 }
206 } else {
207 for (int i = scaleCount-1; i >= 0; i--)
208 if (options.scale > scaleValues[i]) {
209 options.scale = scaleValues[i];
210 break;
211 }
212 }
213 if (options.scale != window->getDesktopScale())
214 window->setDesktopScale(options.scale);
215 }
george824f72ab32006-09-10 05:13:45 +0000216 return true;
217 case IDM_ACTUAL_SIZE:
218 if (options.autoScaling) {
219 options.autoScaling = false;
220 window->setAutoScaling(false);
221 }
george824f72ab32006-09-10 05:13:45 +0000222 options.scale = 100;
223 window->setDesktopScale(100);
224 return true;
225 case IDM_AUTO_SIZE:
george8274ea5f32006-09-11 11:40:12 +0000226 options.autoScaling = !options.autoScaling;
227 window->setAutoScaling(options.autoScaling);
228 if (!options.autoScaling) options.scale = window->getDesktopScale();
george824f72ab32006-09-10 05:13:45 +0000229 return true;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000230 case IDM_SHOW_TOOLBAR:
231 options.showToolbar = !window->isToolbarEnabled();
232 window->setShowToolbar(options.showToolbar);
233 return true;
234 case IDM_CTRL_KEY:
235 window->kbd.keyEvent(this, VK_CONTROL, 0, !window->kbd.keyPressed(VK_CONTROL));
236 return true;
237 case IDM_ALT_KEY:
238 window->kbd.keyEvent(this, VK_MENU, 0, !window->kbd.keyPressed(VK_MENU));
239 return true;
240 case IDM_SEND_MENU_KEY:
241 window->kbd.keyEvent(this, options.menuKey, 0, true);
242 window->kbd.keyEvent(this, options.menuKey, 0, false);
243 return true;
244 case IDM_SEND_CAD:
245 window->kbd.keyEvent(this, VK_CONTROL, 0, true);
246 window->kbd.keyEvent(this, VK_MENU, 0, true);
247 window->kbd.keyEvent(this, VK_DELETE, 0x1000000, true);
248 window->kbd.keyEvent(this, VK_DELETE, 0x1000000, false);
249 window->kbd.keyEvent(this, VK_MENU, 0, false);
250 window->kbd.keyEvent(this, VK_CONTROL, 0, false);
251 return true;
252 case IDM_SEND_CTLESC:
253 window->kbd.keyEvent(this, VK_CONTROL, 0, true);
254 window->kbd.keyEvent(this, VK_ESCAPE, 0, true);
255 window->kbd.keyEvent(this, VK_ESCAPE, 0, false);
256 window->kbd.keyEvent(this, VK_CONTROL, 0, false);
257 return true;
258 case IDM_REQUEST_REFRESH:
259 try {
260 writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
261 requestUpdate = false;
262 } catch (rdr::Exception& e) {
263 close(e.str());
264 }
265 return true;
266 case IDM_NEWCONN:
267 {
268 Thread* newThread = new CConnThread;
269 }
270 return true;
271 case IDM_OPTIONS:
272 // Update the monitor device name in the CConnOptions instance
273 options.monitor.replaceBuf(window->getMonitor());
274 showOptionsDialog();
275 return true;
276 case IDM_INFO:
277 infoDialog.showDialog(this);
278 return true;
279 case IDM_ABOUT:
280 AboutDialog::instance.showDialog();
281 return true;
282 case IDM_FILE_TRANSFER:
283 m_fileTransfer.show(window->getHandle());
284 return true;
285 case IDM_CONN_SAVE_AS:
286 return true;
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000287 };
288 return false;
289}
290
291
292void
293CConn::closeWindow() {
294 vlog.info("window closed");
295 close();
296}
297
298
299void
300CConn::refreshMenu(bool enableSysItems) {
301 HMENU menu = GetSystemMenu(window->getHandle(), FALSE);
302
303 if (!enableSysItems) {
304 // Gray out menu items that might cause a World Of Pain
305 EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
306 EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
307 EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
308 EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
309 EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
310 }
311
312 // Update the modifier key menu items
313 UINT ctrlCheckFlags = window->kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
314 UINT altCheckFlags = window->kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
315 CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
316 CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
317
318 // Ensure that the Send <MenuKey> menu item has the correct text
319 if (options.menuKey) {
320 TCharArray menuKeyStr(options.menuKeyName());
321 TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
322 _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
323 if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
324 InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
325 } else {
326 RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
327 }
328
329 // Set the menu fullscreen option tick
330 CheckMenuItem(menu, IDM_FULLSCREEN, (window->isFullscreen() ? MF_CHECKED : 0) | MF_BYCOMMAND);
331
332 // Set the menu toolbar option tick
333 int toolbarFlags = window->isToolbarEnabled() ? MF_CHECKED : 0;
334 CheckMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
335
336 // In the full-screen mode, "Show toolbar" should be grayed.
337 toolbarFlags = window->isFullscreen() ? MF_GRAYED : MF_ENABLED;
338 EnableMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
339}
340
341
342void
343CConn::blockCallback() {
344 // - An InStream has blocked on I/O while processing an RFB message
345 // We re-enable socket event notifications, so we'll know when more
346 // data is available, then we sit and dispatch window events until
347 // the notification arrives.
348 if (!isClosed()) {
349 if (WSAEventSelect(sock->getFd(), sockEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
350 throw rdr::SystemException("Unable to wait for sokcet data", WSAGetLastError());
351 }
352 while (true) {
353 // If we have closed then we can't block waiting for data
354 if (isClosed())
355 throw rdr::EndOfStream();
356
357 // Wait for socket data, or a message to process
358 DWORD result = MsgWaitForMultipleObjects(1, &sockEvent.h, FALSE, INFINITE, QS_ALLINPUT);
359 if (result == WAIT_OBJECT_0) {
360 // - Network event notification. Return control to I/O routine.
361 break;
362 } else if (result == WAIT_FAILED) {
363 // - The wait operation failed - raise an exception
364 throw rdr::SystemException("blockCallback wait error", GetLastError());
365 }
366
367 // - There should be a message in the message queue
368 MSG msg;
369 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
370 // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
371 // call ToAscii() in CKeyboard::keyEvent(). ToAscii() stores dead key
372 // state from one call to the next, which would be messed up by calls to
373 // TranslateMessage() (actually it looks like TranslateMessage() calls
374 // ToAscii() internally).
375 DispatchMessage(&msg);
376 }
377 }
378
379 // Before we return control to the InStream, reset the network event
380 WSAEventSelect(sock->getFd(), sockEvent, 0);
381 ResetEvent(sockEvent);
382}
383
384
385void CConn::keyEvent(rdr::U32 key, bool down) {
386 if (!options.sendKeyEvents) return;
387 try {
388 writer()->keyEvent(key, down);
389 } catch (rdr::Exception& e) {
390 close(e.str());
391 }
392}
393void CConn::pointerEvent(const Point& pos, int buttonMask) {
394 if (!options.sendPtrEvents) return;
395 try {
396 writer()->pointerEvent(pos, buttonMask);
397 } catch (rdr::Exception& e) {
398 close(e.str());
399 }
400}
401void CConn::clientCutText(const char* str, int len) {
402 if (!options.clientCutText) return;
403 if (state() != RFBSTATE_NORMAL) return;
404 try {
405 writer()->clientCutText(str, len);
406 } catch (rdr::Exception& e) {
407 close(e.str());
408 }
409}
410
411
412CSecurity* CConn::getCSecurity(int secType)
413{
414 switch (secType) {
415 case secTypeNone:
416 return new CSecurityNone();
417 case secTypeVncAuth:
418 return new CSecurityVncAuth(this);
419 default:
420 throw Exception("Unsupported secType?");
421 }
422}
423
424
425void
426CConn::setColourMapEntries(int first, int count, U16* rgbs) {
427 vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
428 int i;
429 for (i=0;i<count;i++)
430 window->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
431 // *** change to 0, 256?
432 window->refreshWindowPalette(first, count);
433}
434
435void
436CConn::bell() {
437 if (options.acceptBell)
438 MessageBeep(-1);
439}
440
441
442void
443CConn::setDesktopSize(int w, int h) {
444 vlog.debug("setDesktopSize %dx%d", w, h);
445
446 // Resize the window's buffer
447 if (window)
448 window->setSize(w, h);
449
450 // Tell the underlying CConnection
451 CConnection::setDesktopSize(w, h);
452}
453
454void
455CConn::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
456 if (!options.useLocalCursor) return;
457
458 // Set the window to use the new cursor
459 window->setCursor(w, h, hotspot, data, mask);
460}
461
462
463void
464CConn::close(const char* reason) {
465 // If already closed then ignore this
466 if (isClosed())
467 return;
468
469 // Hide the window, if it exists
470 if (window)
471 ShowWindow(window->getHandle(), SW_HIDE);
472
473 // Save the reason & flag that we're closed & shutdown the socket
474 isClosed_ = true;
475 closeReason_.replaceBuf(strDup(reason));
476 sock->shutdown();
477}
478
479
480void
481CConn::showOptionsDialog() {
482 optionsDialog.showDialog(this);
483}
484
485
486void
487CConn::framebufferUpdateEnd() {
488 if (debugDelay != 0) {
489 vlog.debug("debug delay %d",(int)debugDelay);
490 UpdateWindow(window->getHandle());
491 Sleep(debugDelay);
492 std::list<rfb::Rect>::iterator i;
493 for (i = debugRects.begin(); i != debugRects.end(); i++) {
494 window->invertRect(*i);
495 }
496 debugRects.clear();
497 }
498 if (options.autoSelect)
499 autoSelectFormatAndEncoding();
500
501 // Always request the next update
502 requestUpdate = true;
503
504 // Check that at least part of the window has changed
505 if (!GetUpdateRect(window->getHandle(), 0, FALSE)) {
506 if (!(GetWindowLong(window->getHandle(), GWL_STYLE) & WS_MINIMIZE))
507 requestNewUpdate();
508 }
509
510 // Make sure the local cursor is shown
511 window->showCursor();
512}
513
514
515// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
516
517// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
518// to the connection speed:
519//
520// Above 16Mbps (timing for at least a second), switch to hextile
521// Otherwise, switch to ZRLE
522//
523// Above 256Kbps, use full colour mode
524//
525void
526CConn::autoSelectFormatAndEncoding() {
527 int kbitsPerSecond = sock->inStream().kbitsPerSecond();
528 unsigned int newEncoding = options.preferredEncoding;
529
530 bool newFullColour = options.fullColour;
531 unsigned int timeWaited = sock->inStream().timeWaited();
532
533 // Select best encoding
534 if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
535 newEncoding = encodingHextile;
536 } else {
537 newEncoding = encodingZRLE;
538 }
539
540 if (newEncoding != options.preferredEncoding) {
541 vlog.info("Throughput %d kbit/s - changing to %s encoding",
542 kbitsPerSecond, encodingName(newEncoding));
543 options.preferredEncoding = newEncoding;
544 encodingChange = true;
545 }
546
547 if (kbitsPerSecond == 0) {
548 return;
549 }
550
551 if (cp.beforeVersion(3, 8)) {
552 // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
553 // cursors "asynchronously". If this happens in the middle of a
554 // pixel format change, the server will encode the cursor with
555 // the old format, but the client will try to decode it
556 // according to the new format. This will lead to a
557 // crash. Therefore, we do not allow automatic format change for
558 // old servers.
559 return;
560 }
561
562 // Select best color level
563 newFullColour = (kbitsPerSecond > 256);
564 if (newFullColour != options.fullColour) {
565 vlog.info("Throughput %d kbit/s - full color is now %s",
566 kbitsPerSecond,
567 newFullColour ? "enabled" : "disabled");
568 options.fullColour = newFullColour;
569 formatChange = true;
570 }
571}
572
573void
574CConn::requestNewUpdate() {
575 if (!requestUpdate) return;
576
577 if (formatChange) {
578 // Select the required pixel format
579 if (options.fullColour) {
580 window->setPF(fullColourPF);
581 } else {
582 switch (options.lowColourLevel) {
583 case 0:
584 window->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
585 break;
586 case 1:
587 window->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
588 break;
589 case 2:
590 window->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
591 break;
592 }
593 }
594
595 // Print the current pixel format
596 char str[256];
597 window->getPF().print(str, 256);
598 vlog.info("Using pixel format %s",str);
599
600 // Save the connection pixel format and tell server to use it
601 cp.setPF(window->getPF());
602 writer()->writeSetPixelFormat(cp.pf());
603
604 // Correct the local window's palette
605 if (!window->getNativePF().trueColour)
606 window->refreshWindowPalette(0, 1 << cp.pf().depth);
607 }
608
609 if (encodingChange) {
610 vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
611 writer()->writeSetEncodings(options.preferredEncoding, true);
612 }
613
614 writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
615 !formatChange);
616
617 encodingChange = formatChange = requestUpdate = false;
618}
619
620
621void
622CConn::calculateFullColourPF() {
623 // If the server is palette based then use palette locally
624 // Also, don't bother doing bgr222
625 if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
626 fullColourPF = serverDefaultPF;
627 options.fullColour = true;
628 } else {
629 // If server is trueColour, use lowest depth PF
630 PixelFormat native = window->getNativePF();
631 if ((serverDefaultPF.bpp < native.bpp) ||
632 ((serverDefaultPF.bpp == native.bpp) &&
633 (serverDefaultPF.depth < native.depth)))
634 fullColourPF = serverDefaultPF;
635 else
636 fullColourPF = window->getNativePF();
637 }
638 formatChange = true;
639}
640
641
642void
643CConn::setName(const char* name) {
644 if (window)
645 window->setName(name);
646 CConnection::setName(name);
647}
648
649
650void CConn::serverInit() {
651 CConnection::serverInit();
652
653 // If using AutoSelect with old servers, start in FullColor
654 // mode. See comment in autoSelectFormatAndEncoding.
655 if (cp.beforeVersion(3, 8) && options.autoSelect) {
656 options.fullColour = true;
657 }
658
659 // Show the window
660 window = new DesktopWindow(this);
661 window->setName(cp.name());
662 window->setSize(cp.width, cp.height);
george82d2c22522006-09-10 11:45:19 +0000663 applyOptions(options);
Constantin Kaplinsky729598c2006-05-25 05:12:25 +0000664
665 // Save the server's current format
666 serverDefaultPF = cp.pf();
667
668 // Calculate the full-colour format to use
669 calculateFullColourPF();
670
671 // Request the initial update
672 vlog.info("requesting initial update");
673 formatChange = encodingChange = requestUpdate = true;
674 requestNewUpdate();
675
676 // Update the window menu
677 HMENU wndmenu = GetSystemMenu(window->getHandle(), FALSE);
678 int toolbarChecked = options.showToolbar ? MF_CHECKED : 0;
679
680 AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
681 AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
682 AppendMenu(wndmenu, MF_STRING | toolbarChecked, IDM_SHOW_TOOLBAR,
683 _T("Show tool&bar"));
684 AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
685 AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
686 AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
687 AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
688 AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
689 AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
690 AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
691 AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
692 AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
693 AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
694 AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
695}
696
697void
698CConn::serverCutText(const char* str, int len) {
699 if (!options.serverCutText) return;
700 window->serverCutText(str, len);
701}
702
703
704void CConn::beginRect(const Rect& r, unsigned int encoding) {
705 sock->inStream().startTiming();
706}
707
708void CConn::endRect(const Rect& r, unsigned int encoding) {
709 sock->inStream().stopTiming();
710 lastUsedEncoding_ = encoding;
711 if (debugDelay != 0) {
712 window->invertRect(r);
713 debugRects.push_back(r);
714 }
715}
716
717void CConn::fillRect(const Rect& r, Pixel pix) {
718 window->fillRect(r, pix);
719}
720void CConn::imageRect(const Rect& r, void* pixels) {
721 window->imageRect(r, pixels);
722}
723void CConn::copyRect(const Rect& r, int srcX, int srcY) {
724 window->copyRect(r, srcX, srcY);
725}
726
727void CConn::getUserPasswd(char** user, char** password) {
728 if (!user && options.passwordFile.buf[0]) {
729 FILE* fp = fopen(options.passwordFile.buf, "rb");
730 if (fp) {
731 char data[256];
732 int datalen = fread(data, 1, 256, fp);
733 fclose(fp);
734 if (datalen == 8) {
735 ObfuscatedPasswd obfPwd;
736 obfPwd.buf = data;
737 obfPwd.length = datalen;
738 PlainPasswd passwd(obfPwd);
739 *password = strDup(passwd.buf);
740 memset(data, 0, strlen(data));
741 }
742 }
743 }
744 if (user && options.userName.buf)
745 *user = strDup(options.userName.buf);
746 if (password && options.password.buf)
747 *password = strDup(options.password.buf);
748 if ((user && !*user) || (password && !*password)) {
749 // Missing username or password - prompt the user
750 UserPasswdDialog userPasswdDialog;
751 userPasswdDialog.setCSecurity(getCurrentCSecurity());
752 userPasswdDialog.getUserPasswd(user, password);
753 }
754 if (user) options.setUserName(*user);
755 if (password) options.setPassword(*password);
756}
757
758bool CConn::processFTMsg(int type) {
759 return m_fileTransfer.processFTMsg(type);
760}