| 1 | /* |
| 2 | * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com> |
| 3 | * |
| 4 | * This library is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU Lesser General Public |
| 6 | * License as published by the Free Software Foundation; either |
| 7 | * version 2.1 of the License, or (at your option) any later version. |
| 8 | * |
| 9 | * This library is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | * Lesser General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Lesser General Public |
| 15 | * License along with this library; if not, write to the Free Software |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| 17 | * |
| 18 | */ |
| 19 | |
| 20 | #include "gpgproc_p.h" |
| 21 | |
| 22 | #ifdef Q_OS_MAC |
| 23 | #define QT_PIPE_HACK |
| 24 | #endif |
| 25 | |
| 26 | using namespace QCA; |
| 27 | |
| 28 | namespace gpgQCAPlugin { |
| 29 | |
| 30 | void releaseAndDeleteLater(QObject *owner, QObject *obj) |
| 31 | { |
| 32 | obj->disconnect(receiver: owner); |
| 33 | obj->setParent(nullptr); |
| 34 | obj->deleteLater(); |
| 35 | } |
| 36 | |
| 37 | GPGProc::Private::Private(GPGProc *_q) |
| 38 | : QObject(_q) |
| 39 | , q(_q) |
| 40 | , pipeAux(this) |
| 41 | , pipeCommand(this) |
| 42 | , pipeStatus(this) |
| 43 | , startTrigger(this) |
| 44 | , doneTrigger(this) |
| 45 | { |
| 46 | qRegisterMetaType<gpgQCAPlugin::GPGProc::Error>(typeName: "gpgQCAPlugin::GPGProc::Error" ); |
| 47 | |
| 48 | proc = nullptr; |
| 49 | proc_relay = nullptr; |
| 50 | startTrigger.setSingleShot(true); |
| 51 | doneTrigger.setSingleShot(true); |
| 52 | |
| 53 | connect(sender: &pipeAux.writeEnd(), signal: &QCA::QPipeEnd::bytesWritten, context: this, slot: &GPGProc::Private::aux_written); |
| 54 | connect(sender: &pipeAux.writeEnd(), signal: &QCA::QPipeEnd::error, context: this, slot: &GPGProc::Private::aux_error); |
| 55 | connect(sender: &pipeCommand.writeEnd(), signal: &QCA::QPipeEnd::bytesWritten, context: this, slot: &GPGProc::Private::command_written); |
| 56 | connect(sender: &pipeCommand.writeEnd(), signal: &QCA::QPipeEnd::error, context: this, slot: &GPGProc::Private::command_error); |
| 57 | connect(sender: &pipeStatus.readEnd(), signal: &QCA::QPipeEnd::readyRead, context: this, slot: &GPGProc::Private::status_read); |
| 58 | connect(sender: &pipeStatus.readEnd(), signal: &QCA::QPipeEnd::error, context: this, slot: &GPGProc::Private::status_error); |
| 59 | connect(sender: &startTrigger, signal: &QCA::SafeTimer::timeout, context: this, slot: &GPGProc::Private::doStart); |
| 60 | connect(sender: &doneTrigger, signal: &QCA::SafeTimer::timeout, context: this, slot: &GPGProc::Private::doTryDone); |
| 61 | |
| 62 | reset(mode: ResetSessionAndData); |
| 63 | } |
| 64 | |
| 65 | GPGProc::Private::~Private() |
| 66 | { |
| 67 | reset(mode: ResetSession); |
| 68 | } |
| 69 | |
| 70 | void GPGProc::Private::closePipes() |
| 71 | { |
| 72 | #ifdef QT_PIPE_HACK |
| 73 | pipeAux.readEnd().reset(); |
| 74 | pipeCommand.readEnd().reset(); |
| 75 | pipeStatus.writeEnd().reset(); |
| 76 | #endif |
| 77 | |
| 78 | pipeAux.reset(); |
| 79 | pipeCommand.reset(); |
| 80 | pipeStatus.reset(); |
| 81 | } |
| 82 | |
| 83 | void GPGProc::Private::reset(ResetMode mode) |
| 84 | { |
| 85 | #ifndef QT_PIPE_HACK |
| 86 | closePipes(); |
| 87 | #endif |
| 88 | |
| 89 | if (proc) { |
| 90 | proc->disconnect(receiver: this); |
| 91 | |
| 92 | if (proc->state() != QProcess::NotRunning) { |
| 93 | // Before try to correct end proccess |
| 94 | // Terminate if failed |
| 95 | proc->close(); |
| 96 | bool finished = proc->waitForFinished(msecs: 5000); |
| 97 | if (!finished) |
| 98 | proc->terminate(); |
| 99 | } |
| 100 | |
| 101 | proc->setParent(nullptr); |
| 102 | releaseAndDeleteLater(owner: this, obj: proc_relay); |
| 103 | proc_relay = nullptr; |
| 104 | delete proc; // should be safe to do thanks to relay |
| 105 | proc = nullptr; |
| 106 | } |
| 107 | |
| 108 | #ifdef QT_PIPE_HACK |
| 109 | closePipes(); |
| 110 | #endif |
| 111 | |
| 112 | startTrigger.stop(); |
| 113 | doneTrigger.stop(); |
| 114 | |
| 115 | pre_stdin.clear(); |
| 116 | pre_aux.clear(); |
| 117 | pre_command.clear(); |
| 118 | pre_stdin_close = false; |
| 119 | pre_aux_close = false; |
| 120 | pre_command_close = false; |
| 121 | |
| 122 | need_status = false; |
| 123 | fin_process = false; |
| 124 | fin_status = false; |
| 125 | |
| 126 | if (mode >= ResetSessionAndData) { |
| 127 | statusBuf.clear(); |
| 128 | statusLines.clear(); |
| 129 | leftover_stdout.clear(); |
| 130 | leftover_stderr.clear(); |
| 131 | error = GPGProc::FailedToStart; |
| 132 | exitCode = -1; |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | bool GPGProc::Private::setupPipes(bool makeAux) |
| 137 | { |
| 138 | if (makeAux && !pipeAux.create()) { |
| 139 | closePipes(); |
| 140 | emit q->debug(QStringLiteral("Error creating pipeAux" )); |
| 141 | return false; |
| 142 | } |
| 143 | |
| 144 | #ifdef QPIPE_SECURE |
| 145 | if (!pipeCommand.create(secure: true)) // secure |
| 146 | #else |
| 147 | if (!pipeCommand.create()) |
| 148 | #endif |
| 149 | { |
| 150 | closePipes(); |
| 151 | emit q->debug(QStringLiteral("Error creating pipeCommand" )); |
| 152 | return false; |
| 153 | } |
| 154 | |
| 155 | if (!pipeStatus.create()) { |
| 156 | closePipes(); |
| 157 | emit q->debug(QStringLiteral("Error creating pipeStatus" )); |
| 158 | return false; |
| 159 | } |
| 160 | |
| 161 | return true; |
| 162 | } |
| 163 | |
| 164 | void GPGProc::Private::setupArguments() |
| 165 | { |
| 166 | QStringList fullargs; |
| 167 | fullargs += QStringLiteral("--no-tty" ); |
| 168 | fullargs += QStringLiteral("--pinentry-mode" ); |
| 169 | fullargs += QStringLiteral("loopback" ); |
| 170 | |
| 171 | if (mode == ExtendedMode) { |
| 172 | fullargs += QStringLiteral("--enable-special-filenames" ); |
| 173 | |
| 174 | fullargs += QStringLiteral("--status-fd" ); |
| 175 | fullargs += QString::number(pipeStatus.writeEnd().idAsInt()); |
| 176 | |
| 177 | fullargs += QStringLiteral("--command-fd" ); |
| 178 | fullargs += QString::number(pipeCommand.readEnd().idAsInt()); |
| 179 | } |
| 180 | |
| 181 | for (int n = 0; n < args.count(); ++n) { |
| 182 | QString a = args[n]; |
| 183 | if (mode == ExtendedMode && a == QLatin1String("-&?" )) |
| 184 | fullargs += QStringLiteral("-&" ) + QString::number(pipeAux.readEnd().idAsInt()); |
| 185 | else |
| 186 | fullargs += a; |
| 187 | } |
| 188 | |
| 189 | QString fullcmd = fullargs.join(QStringLiteral(" " )); |
| 190 | emit q->debug(QStringLiteral("Running: [" ) + bin + QLatin1Char(' ') + fullcmd + QLatin1Char(']')); |
| 191 | |
| 192 | args = fullargs; |
| 193 | } |
| 194 | |
| 195 | void GPGProc::Private::doStart() |
| 196 | { |
| 197 | #ifdef Q_OS_WIN |
| 198 | // Note: for unix, inheritability is set in SProcess |
| 199 | if (pipeAux.readEnd().isValid()) |
| 200 | pipeAux.readEnd().setInheritable(true); |
| 201 | if (pipeCommand.readEnd().isValid()) |
| 202 | pipeCommand.readEnd().setInheritable(true); |
| 203 | if (pipeStatus.writeEnd().isValid()) |
| 204 | pipeStatus.writeEnd().setInheritable(true); |
| 205 | #endif |
| 206 | |
| 207 | setupArguments(); |
| 208 | |
| 209 | proc->start(program: bin, arguments: args); |
| 210 | proc->waitForStarted(); |
| 211 | |
| 212 | pipeAux.readEnd().close(); |
| 213 | pipeCommand.readEnd().close(); |
| 214 | pipeStatus.writeEnd().close(); |
| 215 | } |
| 216 | |
| 217 | void GPGProc::Private::aux_written(int x) |
| 218 | { |
| 219 | emit q->bytesWrittenAux(bytes: x); |
| 220 | } |
| 221 | |
| 222 | void GPGProc::Private::aux_error(QCA::QPipeEnd::Error) |
| 223 | { |
| 224 | emit q->debug(QStringLiteral("Aux: Pipe error" )); |
| 225 | reset(mode: ResetSession); |
| 226 | emit q->error(error: GPGProc::ErrorWrite); |
| 227 | } |
| 228 | |
| 229 | void GPGProc::Private::command_written(int x) |
| 230 | { |
| 231 | emit q->bytesWrittenCommand(bytes: x); |
| 232 | } |
| 233 | |
| 234 | void GPGProc::Private::command_error(QCA::QPipeEnd::Error) |
| 235 | { |
| 236 | emit q->debug(QStringLiteral("Command: Pipe error" )); |
| 237 | reset(mode: ResetSession); |
| 238 | emit q->error(error: GPGProc::ErrorWrite); |
| 239 | } |
| 240 | |
| 241 | void GPGProc::Private::status_read() |
| 242 | { |
| 243 | if (readAndProcessStatusData()) |
| 244 | emit q->readyReadStatusLines(); |
| 245 | } |
| 246 | |
| 247 | void GPGProc::Private::status_error(QCA::QPipeEnd::Error e) |
| 248 | { |
| 249 | if (e == QPipeEnd::ErrorEOF) |
| 250 | emit q->debug(QStringLiteral("Status: Closed (EOF)" )); |
| 251 | else |
| 252 | emit q->debug(QStringLiteral("Status: Closed (gone)" )); |
| 253 | |
| 254 | fin_status = true; |
| 255 | doTryDone(); |
| 256 | } |
| 257 | |
| 258 | void GPGProc::Private::proc_started() |
| 259 | { |
| 260 | emit q->debug(QStringLiteral("Process started" )); |
| 261 | |
| 262 | // Note: we don't close these here anymore. instead we |
| 263 | // do it just after calling proc->start(). |
| 264 | // close these, we don't need them |
| 265 | /*pipeAux.readEnd().close(); |
| 266 | pipeCommand.readEnd().close(); |
| 267 | pipeStatus.writeEnd().close();*/ |
| 268 | |
| 269 | // do the pre* stuff |
| 270 | if (!pre_stdin.isEmpty()) { |
| 271 | proc->write(data: pre_stdin); |
| 272 | pre_stdin.clear(); |
| 273 | } |
| 274 | if (!pre_aux.isEmpty()) { |
| 275 | pipeAux.writeEnd().write(a: pre_aux); |
| 276 | pre_aux.clear(); |
| 277 | } |
| 278 | if (!pre_command.isEmpty()) { |
| 279 | #ifdef QPIPE_SECURE |
| 280 | pipeCommand.writeEnd().writeSecure(a: pre_command); |
| 281 | #else |
| 282 | pipeCommand.writeEnd().write(pre_command); |
| 283 | #endif |
| 284 | pre_command.clear(); |
| 285 | } |
| 286 | |
| 287 | if (pre_stdin_close) { |
| 288 | proc->waitForBytesWritten(); |
| 289 | proc->closeWriteChannel(); |
| 290 | } |
| 291 | |
| 292 | if (pre_aux_close) |
| 293 | pipeAux.writeEnd().close(); |
| 294 | if (pre_command_close) |
| 295 | pipeCommand.writeEnd().close(); |
| 296 | } |
| 297 | |
| 298 | void GPGProc::Private::proc_readyReadStandardOutput() |
| 299 | { |
| 300 | emit q->readyReadStdout(); |
| 301 | } |
| 302 | |
| 303 | void GPGProc::Private::proc_readyReadStandardError() |
| 304 | { |
| 305 | emit q->readyReadStderr(); |
| 306 | } |
| 307 | |
| 308 | void GPGProc::Private::proc_bytesWritten(qint64 lx) |
| 309 | { |
| 310 | int x = (int)lx; |
| 311 | emit q->bytesWrittenStdin(bytes: x); |
| 312 | } |
| 313 | |
| 314 | void GPGProc::Private::proc_finished(int x) |
| 315 | { |
| 316 | emit q->debug(QStringLiteral("Process finished: %1" ).arg(a: x)); |
| 317 | exitCode = x; |
| 318 | |
| 319 | fin_process = true; |
| 320 | fin_process_success = true; |
| 321 | |
| 322 | if (need_status && !fin_status) { |
| 323 | pipeStatus.readEnd().finalize(); |
| 324 | fin_status = true; |
| 325 | if (readAndProcessStatusData()) { |
| 326 | doneTrigger.start(); |
| 327 | emit q->readyReadStatusLines(); |
| 328 | return; |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | doTryDone(); |
| 333 | } |
| 334 | |
| 335 | void GPGProc::Private::proc_error(QProcess::ProcessError x) |
| 336 | { |
| 337 | QMap<int, QString> errmap; |
| 338 | errmap[QProcess::FailedToStart] = QStringLiteral("FailedToStart" ); |
| 339 | errmap[QProcess::Crashed] = QStringLiteral("Crashed" ); |
| 340 | errmap[QProcess::Timedout] = QStringLiteral("Timedout" ); |
| 341 | errmap[QProcess::WriteError] = QStringLiteral("WriteError" ); |
| 342 | errmap[QProcess::ReadError] = QStringLiteral("ReadError" ); |
| 343 | errmap[QProcess::UnknownError] = QStringLiteral("UnknownError" ); |
| 344 | |
| 345 | emit q->debug(QStringLiteral("Process error: %1" ).arg(a: errmap[x])); |
| 346 | |
| 347 | if (x == QProcess::FailedToStart) |
| 348 | error = GPGProc::FailedToStart; |
| 349 | else if (x == QProcess::WriteError) |
| 350 | error = GPGProc::ErrorWrite; |
| 351 | else |
| 352 | error = GPGProc::UnexpectedExit; |
| 353 | |
| 354 | fin_process = true; |
| 355 | fin_process_success = false; |
| 356 | |
| 357 | #ifdef QT_PIPE_HACK |
| 358 | // If the process fails to start, then the ends of the pipes |
| 359 | // intended for the child process are still open. Some Mac |
| 360 | // users experience a lockup if we close our ends of the pipes |
| 361 | // when the child's ends are still open. If we ensure the |
| 362 | // child's ends are closed, we prevent this lockup. I have no |
| 363 | // idea why the problem even happens or why this fix should |
| 364 | // work. |
| 365 | pipeAux.readEnd().reset(); |
| 366 | pipeCommand.readEnd().reset(); |
| 367 | pipeStatus.writeEnd().reset(); |
| 368 | #endif |
| 369 | |
| 370 | if (need_status && !fin_status) { |
| 371 | pipeStatus.readEnd().finalize(); |
| 372 | fin_status = true; |
| 373 | if (readAndProcessStatusData()) { |
| 374 | doneTrigger.start(); |
| 375 | emit q->readyReadStatusLines(); |
| 376 | return; |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | doTryDone(); |
| 381 | } |
| 382 | |
| 383 | void GPGProc::Private::doTryDone() |
| 384 | { |
| 385 | if (!fin_process) |
| 386 | return; |
| 387 | |
| 388 | if (need_status && !fin_status) |
| 389 | return; |
| 390 | |
| 391 | emit q->debug(QStringLiteral("Done" )); |
| 392 | |
| 393 | // get leftover data |
| 394 | proc->setReadChannel(QProcess::StandardOutput); |
| 395 | leftover_stdout = proc->readAll(); |
| 396 | |
| 397 | proc->setReadChannel(QProcess::StandardError); |
| 398 | leftover_stderr = proc->readAll(); |
| 399 | |
| 400 | reset(mode: ResetSession); |
| 401 | if (fin_process_success) |
| 402 | emit q->finished(exitCode); |
| 403 | else |
| 404 | emit q->error(error); |
| 405 | } |
| 406 | |
| 407 | bool GPGProc::Private::readAndProcessStatusData() |
| 408 | { |
| 409 | const QByteArray buf = pipeStatus.readEnd().read(); |
| 410 | if (buf.isEmpty()) |
| 411 | return false; |
| 412 | |
| 413 | return processStatusData(buf); |
| 414 | } |
| 415 | |
| 416 | // return true if there are newly parsed lines available |
| 417 | bool GPGProc::Private::processStatusData(const QByteArray &buf) |
| 418 | { |
| 419 | statusBuf.append(a: buf); |
| 420 | |
| 421 | // extract all lines |
| 422 | QStringList list; |
| 423 | while (true) { |
| 424 | int n = statusBuf.indexOf(ch: '\n'); |
| 425 | if (n == -1) |
| 426 | break; |
| 427 | |
| 428 | // extract the string from statusbuf |
| 429 | ++n; |
| 430 | char *p = (char *)statusBuf.data(); |
| 431 | QByteArray cs(p, n); |
| 432 | const int newsize = statusBuf.size() - n; |
| 433 | memmove(dest: p, src: p + n, n: newsize); |
| 434 | statusBuf.resize(size: newsize); |
| 435 | |
| 436 | // convert to string without newline |
| 437 | QString str = QString::fromUtf8(ba: cs); |
| 438 | str.truncate(pos: str.length() - 1); |
| 439 | |
| 440 | // ensure it has a proper header |
| 441 | if (str.left(n: 9) != QLatin1String("[GNUPG:] " )) |
| 442 | continue; |
| 443 | |
| 444 | // take it off |
| 445 | str = str.mid(position: 9); |
| 446 | |
| 447 | // add to the list |
| 448 | list += str; |
| 449 | } |
| 450 | |
| 451 | if (list.isEmpty()) |
| 452 | return false; |
| 453 | |
| 454 | statusLines += list; |
| 455 | return true; |
| 456 | } |
| 457 | |
| 458 | GPGProc::GPGProc(QObject *parent) |
| 459 | : QObject(parent) |
| 460 | { |
| 461 | d = new Private(this); |
| 462 | } |
| 463 | |
| 464 | GPGProc::~GPGProc() |
| 465 | { |
| 466 | delete d; |
| 467 | } |
| 468 | |
| 469 | void GPGProc::reset() |
| 470 | { |
| 471 | d->reset(mode: ResetAll); |
| 472 | } |
| 473 | |
| 474 | bool GPGProc::isActive() const |
| 475 | { |
| 476 | return (d->proc ? true : false); |
| 477 | } |
| 478 | |
| 479 | void GPGProc::start(const QString &bin, const QStringList &args, Mode mode) |
| 480 | { |
| 481 | if (isActive()) |
| 482 | d->reset(mode: ResetSessionAndData); |
| 483 | |
| 484 | if (mode == ExtendedMode) { |
| 485 | if (!d->setupPipes(args.contains(QStringLiteral("-&?" )))) { |
| 486 | d->error = FailedToStart; |
| 487 | |
| 488 | // emit later |
| 489 | QMetaObject::invokeMethod( |
| 490 | obj: this, member: "error" , c: Qt::QueuedConnection, Q_ARG(gpgQCAPlugin::GPGProc::Error, d->error)); |
| 491 | return; |
| 492 | } |
| 493 | |
| 494 | d->need_status = true; |
| 495 | |
| 496 | emit debug(QStringLiteral("Pipe setup complete" )); |
| 497 | } |
| 498 | |
| 499 | d->proc = new SProcess(d); |
| 500 | |
| 501 | #ifdef Q_OS_UNIX |
| 502 | QList<int> plist; |
| 503 | if (d->pipeAux.readEnd().isValid()) |
| 504 | plist += d->pipeAux.readEnd().id(); |
| 505 | if (d->pipeCommand.readEnd().isValid()) |
| 506 | plist += d->pipeCommand.readEnd().id(); |
| 507 | if (d->pipeStatus.writeEnd().isValid()) |
| 508 | plist += d->pipeStatus.writeEnd().id(); |
| 509 | d->proc->setInheritPipeList(plist); |
| 510 | #endif |
| 511 | |
| 512 | // enable the pipes we want |
| 513 | if (d->pipeAux.writeEnd().isValid()) |
| 514 | d->pipeAux.writeEnd().enable(); |
| 515 | if (d->pipeCommand.writeEnd().isValid()) |
| 516 | d->pipeCommand.writeEnd().enable(); |
| 517 | if (d->pipeStatus.readEnd().isValid()) |
| 518 | d->pipeStatus.readEnd().enable(); |
| 519 | |
| 520 | d->proc_relay = new QProcessSignalRelay(d->proc, d); |
| 521 | connect(sender: d->proc_relay, signal: &QProcessSignalRelay::started, context: d, slot: &GPGProc::Private::proc_started); |
| 522 | connect(sender: d->proc_relay, |
| 523 | signal: &QProcessSignalRelay::readyReadStandardOutput, |
| 524 | context: d, |
| 525 | slot: &GPGProc::Private::proc_readyReadStandardOutput); |
| 526 | connect( |
| 527 | sender: d->proc_relay, signal: &QProcessSignalRelay::readyReadStandardError, context: d, slot: &GPGProc::Private::proc_readyReadStandardError); |
| 528 | connect(sender: d->proc_relay, signal: &QProcessSignalRelay::bytesWritten, context: d, slot: &GPGProc::Private::proc_bytesWritten); |
| 529 | connect(sender: d->proc_relay, signal: &QProcessSignalRelay::finished, context: d, slot: &GPGProc::Private::proc_finished); |
| 530 | connect(sender: d->proc_relay, signal: &QProcessSignalRelay::error, context: d, slot: &GPGProc::Private::proc_error); |
| 531 | |
| 532 | d->bin = bin; |
| 533 | d->args = args; |
| 534 | d->mode = mode; |
| 535 | d->startTrigger.start(); |
| 536 | } |
| 537 | |
| 538 | QByteArray GPGProc::readStdout() |
| 539 | { |
| 540 | if (d->proc) { |
| 541 | d->proc->setReadChannel(QProcess::StandardOutput); |
| 542 | return d->proc->readAll(); |
| 543 | } else { |
| 544 | const QByteArray a = d->leftover_stdout; |
| 545 | d->leftover_stdout.clear(); |
| 546 | return a; |
| 547 | } |
| 548 | } |
| 549 | |
| 550 | QByteArray GPGProc::readStderr() |
| 551 | { |
| 552 | if (d->proc) { |
| 553 | d->proc->setReadChannel(QProcess::StandardError); |
| 554 | return d->proc->readAll(); |
| 555 | } else { |
| 556 | const QByteArray a = d->leftover_stderr; |
| 557 | d->leftover_stderr.clear(); |
| 558 | return a; |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | QStringList GPGProc::readStatusLines() |
| 563 | { |
| 564 | const QStringList out = d->statusLines; |
| 565 | d->statusLines.clear(); |
| 566 | return out; |
| 567 | } |
| 568 | |
| 569 | void GPGProc::writeStdin(const QByteArray &a) |
| 570 | { |
| 571 | if (!d->proc || a.isEmpty()) |
| 572 | return; |
| 573 | |
| 574 | if (d->proc->state() == QProcess::Running) |
| 575 | d->proc->write(data: a); |
| 576 | else |
| 577 | d->pre_stdin += a; |
| 578 | } |
| 579 | |
| 580 | void GPGProc::writeAux(const QByteArray &a) |
| 581 | { |
| 582 | if (!d->proc || a.isEmpty()) |
| 583 | return; |
| 584 | |
| 585 | if (d->proc->state() == QProcess::Running) |
| 586 | d->pipeAux.writeEnd().write(a); |
| 587 | else |
| 588 | d->pre_aux += a; |
| 589 | } |
| 590 | |
| 591 | #ifdef QPIPE_SECURE |
| 592 | void GPGProc::writeCommand(const SecureArray &a) |
| 593 | #else |
| 594 | void GPGProc::writeCommand(const QByteArray &a) |
| 595 | #endif |
| 596 | { |
| 597 | if (!d->proc || a.isEmpty()) |
| 598 | return; |
| 599 | |
| 600 | if (d->proc->state() == QProcess::Running) |
| 601 | #ifdef QPIPE_SECURE |
| 602 | d->pipeCommand.writeEnd().writeSecure(a); |
| 603 | #else |
| 604 | d->pipeCommand.writeEnd().write(a); |
| 605 | #endif |
| 606 | else |
| 607 | d->pre_command += a; |
| 608 | } |
| 609 | |
| 610 | void GPGProc::closeStdin() |
| 611 | { |
| 612 | if (!d->proc) |
| 613 | return; |
| 614 | |
| 615 | if (d->proc->state() == QProcess::Running) { |
| 616 | d->proc->waitForBytesWritten(); |
| 617 | d->proc->closeWriteChannel(); |
| 618 | } else { |
| 619 | d->pre_stdin_close = true; |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | void GPGProc::closeAux() |
| 624 | { |
| 625 | if (!d->proc) |
| 626 | return; |
| 627 | |
| 628 | if (d->proc->state() == QProcess::Running) |
| 629 | d->pipeAux.writeEnd().close(); |
| 630 | else |
| 631 | d->pre_aux_close = true; |
| 632 | } |
| 633 | |
| 634 | void GPGProc::closeCommand() |
| 635 | { |
| 636 | if (!d->proc) |
| 637 | return; |
| 638 | |
| 639 | if (d->proc->state() == QProcess::Running) |
| 640 | d->pipeCommand.writeEnd().close(); |
| 641 | else |
| 642 | d->pre_command_close = true; |
| 643 | } |
| 644 | |
| 645 | } |
| 646 | |