Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications 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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QCoreApplication>
43#include <QDebug>
44#include <QDir>
45#include <QFile>
46#include <QObject>
47#include <QTimer>
48#include "codasignalhandler.h"
49#include "texttracehandler.h"
50
51static const quint64 DEFAULT_CHUNK_SIZE = 40000;
52
53class CodaSignalHandlerPrivate
54{
55 friend class CodaSignalHandler;
56public:
57 CodaSignalHandlerPrivate();
58 ~CodaSignalHandlerPrivate();
59private:
60 SymbianUtils::CodaDevicePtr codaDevice;
61 QEventLoop *eventLoop;
62 QTextStream out;
63 QTextStream err;
64 int loglevel;
65 int timeout;
66 int result;
67 CodaAction action;
68 QString copySrcFileName;
69 QString copyDstFileName;
70 QString dlSrcFileName;
71 QString dlDstFileName;
72 QString appFileName;
73 QString commandLineArgs;
74 QString serialPortName;
75 QString appID;
76 QByteArray remoteFileHandle;
77 QScopedPointer<QFile> localFile;
78 QScopedPointer<QFile> remoteFile;
79 quint64 putChunkSize;
80 quint64 putLastChunkSize;
81 quint64 remoteBytesLeft;
82 quint64 remoteFileSize;
83 bool putWriteOk;
84 bool connected;
85 bool debugSessionControl;
86};
87
88CodaSignalHandlerPrivate::CodaSignalHandlerPrivate()
89 : eventLoop(0),
90 out(stdout),
91 err(stderr),
92 loglevel(0),
93 timeout(0),
94 result(0),
95 action(ActionPingOnly),
96 putChunkSize(DEFAULT_CHUNK_SIZE),
97 putLastChunkSize(0),
98 remoteBytesLeft(0),
99 remoteFileSize(0),
100 putWriteOk(false),
101 connected(false),
102 debugSessionControl(false)
103{
104}
105
106CodaSignalHandlerPrivate::~CodaSignalHandlerPrivate()
107{
108 delete eventLoop;
109 out.flush();
110 err.flush();
111}
112
113void CodaSignalHandler::error(const QString &errorMessage)
114{
115 reportError(tr("CODA error: %1").arg(errorMessage));
116}
117
118void CodaSignalHandler::logMessage(const QString &logMessage)
119{
120 reportMessage(tr("CODA log: %1").arg(logMessage));
121}
122
123void CodaSignalHandler::serialPong(const QString &codaVersion)
124{
125 reportMessage(tr("CODA version: %1").arg(codaVersion));
126}
127
128void CodaSignalHandler::tcfEvent(const Coda::CodaEvent &event)
129{
130 reportMessage(tr("CODA event: Type: %1 Message: %2").arg(event.type()).arg(event.toString()));
131
132 switch (event.type()) {
133 case Coda::CodaEvent::LocatorHello:
134 handleConnected(event);
135 break;
136 case Coda::CodaEvent::ProcessExitedEvent:
137 handleAppExited(event);
138 break;
139 default:
140 reportMessage(tr("CODA unhandled event: Type: %1 Message: %2").arg(event.type()).arg(event.toString()));
141 break;
142 }
143}
144
145void CodaSignalHandler::terminate()
146{
147 if (d->codaDevice) {
148 disconnect(d->codaDevice.data(), 0, this, 0);
149 SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(d->codaDevice);
150 }
151}
152
153void CodaSignalHandler::finished()
154{
155 if (d->eventLoop)
156 d->eventLoop->exit();
157}
158
159void CodaSignalHandler::timeout()
160{
161 reportError(tr("Unable to connect to CODA device. Operation timed out."));
162}
163
164int CodaSignalHandler::run()
165{
166 d->codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(d->serialPortName);
167 bool ok = d->codaDevice && d->codaDevice->device()->isOpen();
168 if (!ok) {
169 QString deviceError = "No such port";
170 if (d->codaDevice)
171 deviceError = d->codaDevice->device()->errorString();
172 reportError(tr("Could not open serial device: %1").arg(deviceError));
173 SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(d->codaDevice);
174 return 1;
175 }
176
177 TextTraceHandler *traceHandler = new TextTraceHandler(
178 SymbianUtils::SymbianDeviceManager::instance()->getOstChannel(d->serialPortName, 2), this);
179
180 if (d->loglevel > 1) {
181 d->codaDevice->setVerbose(1);
182 }
183
184 connect(d->codaDevice.data(), SIGNAL(error(const QString &)), this, SLOT(error(const QString &)));
185 connect(d->codaDevice.data(), SIGNAL(logMessage(const QString &)), this, SLOT(logMessage(const QString &)));
186 connect(d->codaDevice.data(), SIGNAL(serialPong(const QString &)), this, SLOT(serialPong(const QString &)));
187 connect(d->codaDevice.data(), SIGNAL(tcfEvent(const Coda::CodaEvent &)), this, SLOT(tcfEvent(const Coda::CodaEvent &)));
188 connect(this, SIGNAL(done()), this, SLOT(finished()));
189
190 d->codaDevice->sendSerialPing(false);
191 QTimer timer;
192 if (d->timeout > 0) {
193 connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
194 timer.setSingleShot(true);
195 timer.start(d->timeout);
196 }
197 d->eventLoop = new QEventLoop();
198 d->eventLoop->exec();
199 timer.stop();
200 int result = d->result;
201 reportMessage(tr("Done."));
202
203 delete traceHandler;
204 disconnect(d->codaDevice.data(), 0, this, 0);
205 SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(d->codaDevice);
206
207 return result;
208}
209
210void CodaSignalHandler::setActionType(CodaAction action)
211{
212 d->action = CodaAction(d->action | action);
213}
214
215void CodaSignalHandler::setAppFileName(const QString &fileName)
216{
217 d->appFileName = fileName;
218}
219
220void CodaSignalHandler::setCodaDevice(SymbianUtils::CodaDevicePtr &codaDevice)
221{
222 d->codaDevice = codaDevice;
223}
224
225void CodaSignalHandler::setCommandLineArgs(const QString &args)
226{
227 d->commandLineArgs = args;
228}
229
230void CodaSignalHandler::setCopyFileName(const QString &srcName, const QString &dstName)
231{
232 d->copySrcFileName = srcName;
233 d->copyDstFileName = dstName;
234}
235
236void CodaSignalHandler::setDownloadFileName(const QString &srcName, const QString &dstName)
237{
238 d->dlSrcFileName = srcName;
239 d->dlDstFileName = dstName;
240}
241
242void CodaSignalHandler::setLogLevel(int level)
243{
244 d->loglevel = level;
245}
246
247void CodaSignalHandler::setSerialPortName(const QString &serialPortName)
248{
249 d->serialPortName = serialPortName;
250}
251
252void CodaSignalHandler::setTimeout(const int msec)
253{
254 d->timeout = msec;
255}
256
257void CodaSignalHandler::closeFile()
258{
259 d->remoteFile.reset();
260 if (!d->codaDevice) {
261 emit done();
262 return;
263 }
264
265 d->codaDevice->sendFileSystemCloseCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemClose),
266 d->remoteFileHandle);
267}
268
269void CodaSignalHandler::handleConnected(const Coda::CodaEvent &event)
270{
271 if (d->connected)
272 return;
273
274 const Coda::CodaLocatorHelloEvent &hEvent = static_cast<const Coda::CodaLocatorHelloEvent &>(event);
275 QStringList services = hEvent.services();
276 if (services.contains("DebugSessionControl")) {
277 d->debugSessionControl = true;
278 }
279 d->connected = true;
280 handleActions();
281}
282
283void CodaSignalHandler::handleActions()
284{
285 if (d->action & ActionCopy) {
286 initFileSending();
287 } else if (d->action & ActionInstall) {
288 initFileInstallation();
289 } else if (d->action & ActionRun) {
290 initAppRunning();
291 } else if (d->action & ActionDownload) {
292 initFileDownloading();
293 } else {
294 emit done();
295 }
296}
297
298void CodaSignalHandler::handleAppExited(const Coda::CodaEvent &event)
299{
300 const Coda::CodaProcessExitedEvent &pEvent = static_cast<const Coda::CodaProcessExitedEvent &>(event);
301 QString id = pEvent.idString();
302 if (!id.compare(d->appID, Qt::CaseInsensitive)) {
303 d->codaDevice->sendDebugSessionControlSessionEndCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleDebugSessionControlEnd));
304 d->action = static_cast<CodaAction>(d->action & ~ActionRun);
305 handleActions();
306 }
307}
308
309void CodaSignalHandler::handleAppRunning(const Coda::CodaCommandResult &result)
310{
311 if (result.type == Coda::CodaCommandResult::SuccessReply) {
312 reportMessage(tr("Running..."));
313
314 Coda::JsonValue value = result.values.at(0);
315 readAppId(value);
316 } else {
317 reportError(tr("Launch failed: %1").arg(result.toString()));
318 }
319}
320
321void CodaSignalHandler::handleDebugSessionControlEnd(const Coda::CodaCommandResult &result)
322{
323 if (result.type == Coda::CodaCommandResult::SuccessReply) {
324 // nothing to do
325 }
326}
327
328void CodaSignalHandler::handleDebugSessionControlStart(const Coda::CodaCommandResult &result)
329{
330 if (result.type == Coda::CodaCommandResult::SuccessReply) {
331 d->codaDevice->sendRunProcessCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleAppRunning),
332 d->appFileName.toAscii(),
333 d->commandLineArgs.split(' '));
334 reportMessage(tr("Launching %1...").arg(QFileInfo(d->appFileName).fileName()));
335 } else {
336 reportError(tr("Failed to start CODA debug session control."));
337 }
338}
339
340void CodaSignalHandler::handleFileSystemClose(const Coda::CodaCommandResult &result)
341{
342 if (result.type == Coda::CodaCommandResult::SuccessReply) {
343 reportMessage(tr("File closed."));
344 if (d->action & ActionCopy) {
345 d->action = static_cast<CodaAction>(d->action & ~ActionCopy);
346 } else if (d->action & ActionDownload) {
347 d->action = static_cast<CodaAction>(d->action & ~ActionDownload);
348 }
349 handleActions();
350 } else {
351 reportError(tr("Failed to close the remote file: %1").arg(result.toString()));
352 }
353}
354
355void CodaSignalHandler::handleFileSystemOpen(const Coda::CodaCommandResult &result)
356{
357 if (result.type != Coda::CodaCommandResult::SuccessReply) {
358 reportError(tr("Could not open remote file: %1").arg(result.errorString()));
359 return;
360 }
361
362 if (result.values.size() < 1 || result.values.at(0).data().isEmpty()) {
363 reportError(tr("Internal error: No filehandle obtained"));
364 return;
365 }
366
367 if (d->action & ActionCopy) {
368 d->remoteFileHandle = result.values.at(0).data();
369 d->remoteFile.reset(new QFile(d->copySrcFileName));
370 if (!d->remoteFile->open(QIODevice::ReadOnly)) { // Should not fail, was checked before
371 reportError(tr("Could not open local file %1").arg(d->copySrcFileName));
372 return;
373 }
374 putSendNextChunk();
375 } else if (d->action & ActionDownload) {
376 d->remoteFileHandle = result.values.at(0).data();
377 d->localFile.reset(new QFile(d->dlDstFileName));
378 // remove any existing file with the same name
379 if (d->localFile->exists() && !d->localFile->remove()) {
380 reportError(tr("Could not create host file: %1 due to error: %2").arg(d->localFile->fileName(), d->localFile->errorString()));
381 return;
382 }
383 // open local file in write-only mode
384 if (!d->localFile->open(QFile::WriteOnly)) {
385 reportError(tr("Could not open host file for writing: %1 due to error: %2").arg(d->localFile->fileName(), d->localFile->errorString()));
386 return;
387 }
388 d->codaDevice->sendFileSystemFstatCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemStart),
389 d->remoteFileHandle);
390 }
391}
392
393void CodaSignalHandler::handleFileSystemRead(const Coda::CodaCommandResult &result)
394{
395 if (result.type != Coda::CodaCommandResult::SuccessReply || result.values.size() != 2) {
396 reportError(tr("Could not read remote file: %1").arg(result.errorString()));
397 return;
398 }
399
400 QByteArray data = QByteArray::fromBase64(result.values.at(0).data());
401 bool eof = result.values.at(1).toVariant().toBool();
402 qint64 written = d->localFile->write(data);
403 if (written < 0) {
404 reportError(tr("Could not write data to host file: %1 due to error: %2").arg(d->localFile->fileName(), d->localFile->errorString()));
405 return;
406 }
407
408 d->remoteBytesLeft -= written;
409 if (!eof && d->remoteBytesLeft > 0) {
410 readNextChunk();
411 }
412 else {
413 d->localFile->flush();
414 d->localFile->close();
415 closeFile();
416 }
417}
418
419void CodaSignalHandler::handleFileSystemStart(const Coda::CodaCommandResult &result)
420{
421 if (result.type != Coda::CodaCommandResult::SuccessReply) {
422 reportError(tr("Could not open remote file: %1").arg(result.errorString()));
423 return;
424 }
425
426 if (result.values.size() < 1 || result.values.at(0).children().isEmpty()) {
427 reportError(tr("Could not get file attributes"));
428 return;
429 }
430
431 Coda::JsonValue val = result.values.at(0).findChild("Size");
432 d->remoteFileSize = val.isValid() ? val.data().toLong() : -1L;
433 if (d->remoteFileSize < 0) {
434 reportError(tr("Could not get file size"));
435 return;
436 }
437
438 d->remoteBytesLeft = d->remoteFileSize;
439 readNextChunk();
440}
441
442void CodaSignalHandler::handleFileSystemWrite(const Coda::CodaCommandResult &result)
443{
444 // Close remote file even if copy fails
445 d->putWriteOk = result;
446 if (!d->putWriteOk) {
447 QString fileName = QFileInfo(d->copyDstFileName).fileName();
448 reportError(tr("Could not write to file %1 on device: %2").arg(fileName).arg(result.errorString()));
449 }
450
451 if (!d->putWriteOk || d->putLastChunkSize < d->putChunkSize) {
452 closeFile();
453 } else {
454 putSendNextChunk();
455 }
456}
457
458void CodaSignalHandler::handleSymbianInstall(const Coda::CodaCommandResult &result)
459{
460 if (result.type == Coda::CodaCommandResult::SuccessReply) {
461 reportMessage(tr("Installation has finished."));
462 d->action = static_cast<CodaAction>(d->action & ~ActionInstall);
463 handleActions();
464 } else {
465 reportError(tr("Installation failed: %1").arg(result.errorString()));
466 }
467}
468
469void CodaSignalHandler::initAppRunning()
470{
471 if (!d->codaDevice || d->appFileName.isEmpty()) {
472 emit done();
473 return;
474 }
475
476 if (!d->debugSessionControl) {
477 reportError(tr("CODA DebugSessionControl service not found, please update to CODA v4.0.23 or later."));
478 }
479
480 d->codaDevice->sendDebugSessionControlSessionStartCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleDebugSessionControlStart));
481}
482
483void CodaSignalHandler::initFileDownloading()
484{
485 if (!d->codaDevice || d->dlSrcFileName.isEmpty()) {
486 emit done();
487 return;
488 }
489
490 d->codaDevice->sendFileSystemOpenCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemOpen),
491 d->dlSrcFileName.toAscii(), Coda::CodaDevice::FileSystem_TCF_O_READ);
492 reportMessage(tr("Downloading %1...").arg(QFileInfo(d->dlSrcFileName).fileName()));
493}
494
495void CodaSignalHandler::initFileInstallation()
496{
497 if (!d->codaDevice || d->copyDstFileName.isEmpty()) {
498 emit done();
499 return;
500 }
501
502 QString installationDrive = "C";
503 d->codaDevice->sendSymbianInstallSilentInstallCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleSymbianInstall),
504 d->copyDstFileName.toAscii(),
505 installationDrive.toAscii());
506 reportMessage(tr("Installing package \"%1\" on drive %2...").arg(QFileInfo(d->copyDstFileName).fileName(), installationDrive));
507}
508
509void CodaSignalHandler::initFileSending()
510{
511 if (!d->codaDevice || d->copySrcFileName.isEmpty()) {
512 emit done();
513 return;
514 }
515
516 const unsigned flags =
517 Coda::CodaDevice::FileSystem_TCF_O_WRITE
518 |Coda::CodaDevice::FileSystem_TCF_O_CREAT
519 |Coda::CodaDevice::FileSystem_TCF_O_TRUNC;
520 d->putWriteOk = false;
521 d->codaDevice->sendFileSystemOpenCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemOpen),
522 d->copyDstFileName.toAscii(), flags);
523 reportMessage(tr("Copying %1...").arg(QFileInfo(d->copyDstFileName).fileName()));
524}
525
526void CodaSignalHandler::putSendNextChunk()
527{
528 if (!d->codaDevice || !d->remoteFile) {
529 emit done();
530 return;
531 }
532
533 // Read and send off next chunk
534 const quint64 pos = d->remoteFile->pos();
535 const QByteArray data = d->remoteFile->read(d->putChunkSize);
536 if (data.isEmpty()) {
537 d->putWriteOk = true;
538 closeFile();
539 } else {
540 d->putLastChunkSize = data.size();
541 d->codaDevice->sendFileSystemWriteCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemWrite),
542 d->remoteFileHandle, data, unsigned(pos));
543 }
544}
545
546void CodaSignalHandler::readNextChunk()
547{
548 const quint64 pos = d->remoteFileSize - d->remoteBytesLeft;
549 const quint64 size = qMin(d->remoteBytesLeft, DEFAULT_CHUNK_SIZE);
550 d->codaDevice->sendFileSystemReadCommand(Coda::CodaCallback(this, &CodaSignalHandler::handleFileSystemRead),
551 d->remoteFileHandle, pos, size);
552}
553
554void CodaSignalHandler::readAppId(Coda::JsonValue value)
555{
556 if (value.isObject()) {
557 Coda::JsonValue idValue = value.findChild("ID");
558 if (idValue.isString()) {
559 d->appID = idValue.data();
560 return;
561 }
562 }
563
564 reportError(tr("Could not get process ID of %1.").arg(QFileInfo(d->appFileName).fileName()));
565}
566
567void CodaSignalHandler::reportError(const QString &message)
568{
569 d->err << message << endl;
570 d->result = 1;
571 emit done();
572}
573
574void CodaSignalHandler::reportMessage(const QString &message)
575{
576 if (d->loglevel > 0)
577 d->out << message << endl;
578}
579
580CodaSignalHandler::CodaSignalHandler()
581 : d(new CodaSignalHandlerPrivate())
582{
583}
584
585CodaSignalHandler::~CodaSignalHandler()
586{
587 delete d;
588}
589
590

Warning: That file was not part of the compilation database. It may have many parsing errors.