1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qwscommand_qws_p.h"
43 #include "qtransportauth_qws.h"
44 #include "qtransportauth_qws_p.h"
45 
46 #include <unistd.h>
47 
48 // #define QWSCOMMAND_DEBUG 1 // Uncomment to debug client/server communication
49 
50 #ifdef QWSCOMMAND_DEBUG
51 # include <qdebug.h>
52 # include "qfile.h"
53 # include <ctype.h>
54 #endif
55 
56 QT_BEGIN_NAMESPACE
57 
58 #ifdef QWSCOMMAND_DEBUG
59 // QWSHexDump -[ start ]---------------------------------------------
60 # define QWSHEXDUMP_MAX 32
61 class QWSHexDump
62 {
63 public:
64 
QWSHexDump(const void * address,int len,int wrapAt=16)65     QWSHexDump(const void *address, int len, int wrapAt = 16)
66         : wrap(wrapAt), dataSize(len)
67     {
68         init();
69         data = reinterpret_cast<const char*>(address);
70         if (len < 0)
71             dataSize = 0;
72     }
73 
QWSHexDump(const char * str,int len=-1,int wrapAt=16)74     QWSHexDump(const char *str, int len = -1, int wrapAt = 16)
75         : wrap(wrapAt), dataSize(len)
76     {
77         init();
78         data = str;
79         if (len == -1)
80             dataSize = str ? strlen(str) : 0;
81     }
82 
QWSHexDump(const QByteArray & array,int wrapAt=16)83     QWSHexDump(const QByteArray &array, int wrapAt = 16)
84         : wrap(wrapAt)
85     {
86         init();
87         data = array.data();
88         dataSize = array.size();
89     }
90 
91     // Sets a customized prefix for the hexdump
setPrefix(const char * str)92     void setPrefix(const char *str) { prefix = str; }
93 
94     // Sets number of bytes to cluster together
setClusterSize(uint num)95     void setClusterSize(uint num) { clustering = num; }
96 
97     // Output hexdump to a text stream
intoTextStream(QTextStream & strm)98     void intoTextStream(QTextStream &strm) {
99         outstrm = &strm;
100         hexDump();
101     }
102 
103     // Output hexdump to a QString
104     QString toString();
105 
106 protected:
107     void init();
108     void hexDump();
109     void sideviewDump(int at);
110 
111 private:
112     uint wrap;
113     uint clustering;
114     uint dataSize;
115     int dataWidth;
116     const char *data;
117     const char *prefix;
118     bool dirty;
119 
120     char sideviewLayout[QWSHEXDUMP_MAX + 1];
121     char sideview[15];
122 
123     QTextStream *outstrm;
124 };
125 
init()126 void QWSHexDump::init()
127 {
128     prefix = "> ";             // Standard line prefix
129     clustering = 2;            // Word-size clustering by default
130     if (wrap > QWSHEXDUMP_MAX) // No wider than QWSHexDump_MAX bytes
131         wrap = QWSHEXDUMP_MAX;
132 }
133 
hexDump()134 void QWSHexDump::hexDump()
135 {
136     *outstrm << '(' << dataSize << " bytes):\n" << prefix;
137     sprintf(sideviewLayout, " [%%-%us]", wrap);
138     dataWidth = (2 * wrap) + (wrap / clustering);
139 
140     dirty = false;
141     uint wrapIndex = 0;
142     for (uint i = 0; i < dataSize; i++) {
143         uint c = static_cast<uchar>(data[i]);
144         sideview[wrapIndex = i%wrap] = isprint(c) ? c : '.';
145 
146         if (wrapIndex && (wrapIndex % clustering == 0))
147             *outstrm << ' ';
148 
149         outstrm->setFieldWidth(2);
150         outstrm->setPadChar('0');
151         outstrm->setNumberFlags( QTextStream::ShowBase );
152         *outstrm << hex << c;
153         dirty = true;
154 
155         if (wrapIndex == wrap-1) {
156             sideviewDump(wrapIndex);
157             wrapIndex = 0;
158             if (i+1 < dataSize)
159                 *outstrm << endl << prefix;
160         }
161 
162     }
163     sideviewDump(wrapIndex);
164 }
165 
sideviewDump(int at)166 void QWSHexDump::sideviewDump(int at)
167 {
168     if (dirty) {
169         dirty = false;
170         ++at;
171         sideview[at] = '\0';
172         int currentWidth = (2 * at) + (at / clustering) - (at%clustering?0:1);
173         int missing = qMax(dataWidth - currentWidth, 0);
174         while (missing--)
175             *outstrm << ' ';
176 
177         *outstrm << " [";
178         outstrm->setPadChar(' ');
179         outstrm->setFieldWidth(wrap);
180         outstrm->setFieldAlignment( QTextStream::AlignLeft );
181         *outstrm << sideview;
182         *outstrm << ']';
183     }
184 }
185 
186 // Output hexdump to a QString
toString()187 QString QWSHexDump::toString() {
188     QString result;
189     QTextStream strm(&result, QFile::WriteOnly);
190     outstrm = &strm;
191     hexDump();
192     return result;
193 }
194 
195 #ifndef QT_NO_DEBUG
operator <<(QDebug & dbg,QWSHexDump * hd)196 QDebug &operator<<(QDebug &dbg, QWSHexDump *hd) {
197     if (!hd)
198         return dbg << "QWSHexDump(0x0)";
199     QString result = hd->toString();
200     dbg.nospace() << result;
201     return dbg.space();
202 }
203 
204 // GCC & Intel wont handle references here
operator <<(QDebug dbg,QWSHexDump hd)205 QDebug operator<<(QDebug dbg, QWSHexDump hd) {
206     return dbg << &hd;
207 }
208 #endif
209 // QWSHexDump -[ end ]-----------------------------------------------
210 
211 
operator <<(QDebug & dbg,QWSCommand::Type tp)212 QDebug &operator<<(QDebug &dbg, QWSCommand::Type tp)
213 {
214     dbg << qws_getCommandTypeString( tp );
215     return dbg;
216 }
217 
218 #define N_EVENTS 19
219 const char * eventNames[N_EVENTS] =  {
220         "NoEvent",
221         "Connected",
222         "Mouse", "Focus", "Key",
223         "Region",
224         "Creation",
225         "PropertyNotify",
226         "PropertyReply",
227         "SelectionClear",
228         "SelectionRequest",
229         "SelectionNotify",
230         "MaxWindowRect",
231         "QCopMessage",
232         "WindowOperation",
233         "IMEvent",
234         "IMQuery",
235         "IMInit",
236         "Font"
237     };
238 
239 class QWSServer;
240 extern QWSServer *qwsServer;
241 #endif
242 
qws_getCommandTypeString(QWSCommand::Type tp)243 const char *qws_getCommandTypeString( QWSCommand::Type tp )
244 {
245     const char *typeStr;
246     switch(tp) {
247         case QWSCommand::Create:
248             typeStr = "Create";
249             break;
250         case QWSCommand::Shutdown:
251             typeStr = "Shutdown";
252             break;
253         case QWSCommand::Region:
254             typeStr = "Region";
255             break;
256         case QWSCommand::RegionMove:
257             typeStr = "RegionMove";
258             break;
259         case QWSCommand::RegionDestroy:
260             typeStr = "RegionDestroy";
261             break;
262         case QWSCommand::SetProperty:
263             typeStr = "SetProperty";
264             break;
265         case QWSCommand::AddProperty:
266             typeStr = "AddProperty";
267             break;
268         case QWSCommand::RemoveProperty:
269             typeStr = "RemoveProperty";
270             break;
271         case QWSCommand::GetProperty:
272             typeStr = "GetProperty";
273             break;
274         case QWSCommand::SetSelectionOwner:
275             typeStr = "SetSelectionOwner";
276             break;
277         case QWSCommand::ConvertSelection:
278             typeStr = "ConvertSelection";
279             break;
280         case QWSCommand::RequestFocus:
281             typeStr = "RequestFocus";
282             break;
283         case QWSCommand::ChangeAltitude:
284             typeStr = "ChangeAltitude";
285             break;
286         case QWSCommand::SetOpacity:
287             typeStr = "SetOpacity";
288             break;
289         case QWSCommand::DefineCursor:
290             typeStr = "DefineCursor";
291             break;
292         case QWSCommand::SelectCursor:
293             typeStr = "SelectCursor";
294             break;
295         case QWSCommand::PositionCursor:
296             typeStr = "PositionCursor";
297             break;
298         case QWSCommand::GrabMouse:
299             typeStr = "GrabMouse";
300             break;
301         case QWSCommand::PlaySound:
302             typeStr = "PlaySound";
303             break;
304         case QWSCommand::QCopRegisterChannel:
305             typeStr = "QCopRegisterChannel";
306             break;
307         case QWSCommand::QCopSend:
308             typeStr = "QCopSend";
309             break;
310         case QWSCommand::RegionName:
311             typeStr = "RegionName";
312             break;
313         case QWSCommand::Identify:
314             typeStr = "Identify";
315             break;
316         case QWSCommand::GrabKeyboard:
317             typeStr = "GrabKeyboard";
318             break;
319         case QWSCommand::RepaintRegion:
320             typeStr = "RepaintRegion";
321             break;
322         case QWSCommand::IMMouse:
323             typeStr = "IMMouse";
324             break;
325         case QWSCommand::IMUpdate:
326             typeStr = "IMUpdate";
327             break;
328         case QWSCommand::IMResponse:
329             typeStr = "IMResponse";
330             break;
331         case QWSCommand::Font:
332             typeStr = "Font";
333             break;
334         case QWSCommand::Unknown:
335         default:
336             typeStr = "Unknown";
337             break;
338     }
339     return typeStr;
340 }
341 
342 
343 /*********************************************************************
344  *
345  * Functions to read/write commands on/from a socket
346  *
347  *********************************************************************/
348 
349 #ifndef QT_NO_QWS_MULTIPROCESS
qws_write_command(QIODevice * socket,int type,char * simpleData,int simpleLen,char * rawData,int rawLen)350 void qws_write_command(QIODevice *socket, int type, char *simpleData, int simpleLen,
351                        char *rawData, int rawLen)
352 {
353 #ifdef QWSCOMMAND_DEBUG
354     if (simpleLen) qDebug() << "WRITE simpleData " << QWSHexDump(simpleData, simpleLen);
355     if (rawLen > 0) qDebug() << "WRITE rawData " << QWSHexDump(rawData, rawLen);
356 #endif
357 
358 #ifndef QT_NO_SXE
359     QTransportAuth *a = QTransportAuth::getInstance();
360     // ###### as soon as public API can be modified get rid of horrible casts
361     QIODevice *ad = a->passThroughByClient(reinterpret_cast<QWSClient*>(socket));
362     if (ad)
363         socket = ad;
364 #endif
365 
366     qws_write_uint(socket, type);
367 
368     if (rawLen > MAX_COMMAND_SIZE) {
369         qWarning("qws_write_command: Message of size %d too big. "
370                  "Truncated to %d", rawLen, MAX_COMMAND_SIZE);
371         rawLen = MAX_COMMAND_SIZE;
372     }
373 
374     qws_write_uint(socket, rawLen == -1 ? 0 : rawLen);
375 
376     if (simpleData && simpleLen)
377         socket->write(simpleData, simpleLen);
378 
379     if (rawLen && rawData)
380         socket->write(rawData, rawLen);
381 }
382 
383 /*
384   command format: [type][rawLen][simpleData][rawData]
385   type is already read when entering this function
386 */
387 
qws_read_command(QIODevice * socket,char * & simpleData,int & simpleLen,char * & rawData,int & rawLen,int & bytesRead)388 bool qws_read_command(QIODevice *socket, char *&simpleData, int &simpleLen,
389                       char *&rawData, int &rawLen, int &bytesRead)
390 {
391 
392     // read rawLen
393     if (rawLen == -1) {
394         rawLen = qws_read_uint(socket);
395         if (rawLen == -1)
396             return false;
397     }
398 
399     // read simpleData, assumes socket is capable of buffering all the data
400     if (simpleLen && !rawData) {
401         if (socket->bytesAvailable() < uint(simpleLen))
402             return false;
403         int tmp = socket->read(simpleData, simpleLen);
404         Q_ASSERT(tmp == simpleLen);
405         Q_UNUSED(tmp);
406     }
407 
408     if (rawLen > MAX_COMMAND_SIZE) {
409         socket->close();
410         qWarning("qws_read_command: Won't read command of length %d, "
411                  "connection closed.", rawLen);
412         return false;
413     }
414 
415     // read rawData
416     if (rawLen && !rawData) {
417         rawData = new char[rawLen];
418         bytesRead = 0;
419     }
420     if (bytesRead < rawLen && socket->bytesAvailable())
421         bytesRead += socket->read(rawData + bytesRead, rawLen - bytesRead);
422 
423     return (bytesRead == rawLen);
424 }
425 #endif
426 
427 /*********************************************************************
428  *
429  * QWSCommand base class - only use derived classes from that
430  *
431  *********************************************************************/
~QWSProtocolItem()432 QWSProtocolItem::~QWSProtocolItem() {
433     if (deleteRaw)
434         delete []rawDataPtr;
435 }
436 
437 #ifndef QT_NO_QWS_MULTIPROCESS
write(QIODevice * s)438 void QWSProtocolItem::write(QIODevice *s) {
439 #ifdef QWSCOMMAND_DEBUG
440     if (!qwsServer)
441         qDebug() << "QWSProtocolItem::write sending type " << static_cast<QWSCommand::Type>(type);
442     else
443         qDebug() << "QWSProtocolItem::write sending event " << (type < N_EVENTS ? eventNames[type] : "unknown");
444 #endif
445     qws_write_command(s, type, simpleDataPtr, simpleLen, rawDataPtr, rawLen);
446 }
447 
read(QIODevice * s)448 bool QWSProtocolItem::read(QIODevice *s) {
449 #ifdef QWSCOMMAND_DEBUG
450     QLatin1String reread( (rawLen == -1) ? "" : "REREAD");
451     if (qwsServer)
452         qDebug() << "QWSProtocolItem::read reading type " << static_cast<QWSCommand::Type>(type) << reread;
453     else
454         qDebug() << "QWSProtocolItem::read reading event " << (type < N_EVENTS ? eventNames[type] : "unknown") << reread;
455     //qDebug("QWSProtocolItem::read reading event %s", type < N_EVENTS ? eventNames[type] : "unknown");
456 #endif
457     bool b = qws_read_command(s, simpleDataPtr, simpleLen, rawDataPtr, rawLen, bytesRead);
458     if (b) {
459         setData(rawDataPtr, rawLen, false);
460         deleteRaw = true;
461     }
462 #ifdef QWSCOMMAND_DEBUG
463     else
464     {
465         qDebug() << "error in reading command " << static_cast<QWSCommand::Type>(type);
466     }
467 #endif
468     return b;
469 }
470 #endif // QT_NO_QWS_MULTIPROCESS
471 
copyFrom(const QWSProtocolItem * item)472 void QWSProtocolItem::copyFrom(const QWSProtocolItem *item) {
473     if (this == item)
474         return;
475     simpleLen = item->simpleLen;
476     memcpy(simpleDataPtr, item->simpleDataPtr, simpleLen);
477     setData(item->rawDataPtr, item->rawLen);
478 }
479 
setData(const char * data,int len,bool allocateMem)480 void QWSProtocolItem::setData(const char *data, int len, bool allocateMem) {
481     if (deleteRaw)
482         delete [] rawDataPtr;
483     if (!data || len <= 0) {
484         rawDataPtr = 0;
485         rawLen = 0;
486         return;
487     }
488     if (allocateMem) {
489         rawDataPtr = new char[len];
490         memcpy(rawDataPtr, data, len);
491         deleteRaw = true;
492     } else {
493         rawDataPtr = const_cast<char *>(data);
494         deleteRaw = false;
495     }
496     rawLen = len;
497 }
498 
factory(int type)499 QWSCommand *QWSCommand::factory(int type)
500 {
501     QWSCommand *command = 0;
502     switch (type) {
503     case QWSCommand::Create:
504         command = new QWSCreateCommand;
505         break;
506     case QWSCommand::Shutdown:
507         command = new QWSCommand(type, 0, 0);
508         break;
509     case QWSCommand::Region:
510         command = new QWSRegionCommand;
511         break;
512     case QWSCommand::RegionMove:
513         command = new QWSRegionMoveCommand;
514         break;
515     case QWSCommand::RegionDestroy:
516         command = new QWSRegionDestroyCommand;
517         break;
518     case QWSCommand::AddProperty:
519         command = new QWSAddPropertyCommand;
520         break;
521     case QWSCommand::SetProperty:
522         command = new QWSSetPropertyCommand;
523         break;
524     case QWSCommand::RemoveProperty:
525         command = new QWSRemovePropertyCommand;
526         break;
527     case QWSCommand::GetProperty:
528         command = new QWSGetPropertyCommand;
529         break;
530     case QWSCommand::SetSelectionOwner:
531         command = new QWSSetSelectionOwnerCommand;
532         break;
533     case QWSCommand::RequestFocus:
534         command = new QWSRequestFocusCommand;
535         break;
536     case QWSCommand::ChangeAltitude:
537         command = new QWSChangeAltitudeCommand;
538         break;
539     case QWSCommand::SetOpacity:
540         command = new QWSSetOpacityCommand;
541         break;
542     case QWSCommand::DefineCursor:
543         command = new QWSDefineCursorCommand;
544         break;
545     case QWSCommand::SelectCursor:
546         command = new QWSSelectCursorCommand;
547         break;
548     case QWSCommand::GrabMouse:
549         command = new QWSGrabMouseCommand;
550         break;
551     case QWSCommand::GrabKeyboard:
552         command = new QWSGrabKeyboardCommand;
553         break;
554 #ifndef QT_NO_SOUND
555     case QWSCommand::PlaySound:
556         command = new QWSPlaySoundCommand;
557         break;
558 #endif
559 #ifndef QT_NO_COP
560     case QWSCommand::QCopRegisterChannel:
561         command = new QWSQCopRegisterChannelCommand;
562         break;
563     case QWSCommand::QCopSend:
564         command = new QWSQCopSendCommand;
565         break;
566 #endif
567     case QWSCommand::RegionName:
568         command = new QWSRegionNameCommand;
569         break;
570     case QWSCommand::Identify:
571         command = new QWSIdentifyCommand;
572         break;
573     case QWSCommand::RepaintRegion:
574         command = new QWSRepaintRegionCommand;
575         break;
576 #ifndef QT_NO_QWS_INPUTMETHODS
577     case QWSCommand::IMUpdate:
578         command = new QWSIMUpdateCommand;
579         break;
580 
581     case QWSCommand::IMMouse:
582         command = new QWSIMMouseCommand;
583         break;
584 
585     case QWSCommand::IMResponse:
586         command = new QWSIMResponseCommand;
587         break;
588 #endif
589     case QWSCommand::PositionCursor:
590         command = new QWSPositionCursorCommand;
591         break;
592 #ifndef QT_NO_QWSEMBEDWIDGET
593     case QWSCommand::Embed:
594         command = new QWSEmbedCommand;
595         break;
596 #endif
597     case QWSCommand::Font:
598         command = new QWSFontCommand;
599         break;
600     case QWSCommand::ScreenTransform:
601         command = new QWSScreenTransformCommand;
602         break;
603     default:
604         qWarning("QWSCommand::factory : Type error - got %08x!", type);
605     }
606     return command;
607 }
608 
609 QT_END_NAMESPACE
610