1/***************************************************************************
2 * Copyright (C) 2013 by Volker Krause <vkrause@kde.org> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU Library General Public License as *
6 * published by the Free Software Foundation; either version 2 of the *
7 * License, or (at your option) any later version. *
8 * *
9 * This program 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 *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Library General Public *
15 * License along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
19
20#include "session.h"
21
22#include <shared/akstandarddirs.h>
23#include <shared/akdebug.h>
24
25#include <QCoreApplication>
26#include <QDebug>
27#include <QFile>
28#include <QSocketNotifier>
29#include <QSettings>
30#include <QLocalSocket>
31
32#include <iostream>
33#include <fcntl.h>
34#include <unistd.h>
35
36Session::Session(const QString &input, QObject *parent)
37 : QObject(parent)
38 , m_input(0)
39 , m_session(0)
40 , m_notifier(0)
41 , m_receivedBytes(0)
42 , m_sentBytes(0)
43{
44 QFile *file = new QFile(this);
45 if (input != QLatin1String("-")) {
46 file->setFileName(input);
47 if (!file->open(QFile::ReadOnly)) {
48 akFatal() << "Failed to open" << input;
49 }
50 } else {
51 // ### does that work on Windows?
52 const int flags = fcntl(0, F_GETFL);
53 fcntl(0, F_SETFL, flags | O_NONBLOCK);
54
55 if (!file->open(stdin, QFile::ReadOnly | QFile::Unbuffered)) {
56 akFatal() << "Failed to open stdin!";
57 }
58 m_notifier = new QSocketNotifier(0, QSocketNotifier::Read, this);
59 connect(m_notifier, SIGNAL(activated(int)), SLOT(inputAvailable()));
60 }
61 m_input = file;
62}
63
64Session::~Session()
65{
66}
67
68void Session::connectToHost()
69{
70 const QSettings connectionSettings(AkStandardDirs::connectionConfigFile(), QSettings::IniFormat);
71
72 QString serverAddress;
73#ifdef Q_OS_WIN
74 serverAddress = connectionSettings.value(QLatin1String("Data/NamedPipe"), QString()).toString();
75#else
76 serverAddress = connectionSettings.value(QLatin1String("Data/UnixPath"), QString()).toString();
77#endif
78 if (serverAddress.isEmpty()) {
79 akFatal() << "Unable to determine server address.";
80 }
81
82 QLocalSocket *socket = new QLocalSocket(this);
83 connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)), SLOT(serverError(QLocalSocket::LocalSocketError)));
84 connect(socket, SIGNAL(disconnected()), SLOT(serverDisconnected()));
85 connect(socket, SIGNAL(readyRead()), SLOT(serverRead()));
86 connect(socket, SIGNAL(connected()), SLOT(inputAvailable()));
87
88 m_session = socket;
89 socket->connectToServer(serverAddress);
90
91 m_connectionTime.start();
92}
93
94void Session::inputAvailable()
95{
96 if (!m_session->isOpen()) {
97 return;
98 }
99
100 if (m_notifier) {
101 m_notifier->setEnabled(false);
102 }
103
104 if (m_input->atEnd()) {
105 return;
106 }
107
108 QByteArray buffer(1024, Qt::Uninitialized);
109 qint64 readSize = 0;
110
111 while ((readSize = m_input->read(buffer.data(), buffer.size())) > 0) {
112 m_session->write(buffer.constData(), readSize);
113 m_sentBytes += readSize;
114 }
115
116 if (m_notifier) {
117 m_notifier->setEnabled(true);
118 }
119}
120
121void Session::serverDisconnected()
122{
123 QCoreApplication::exit(0);
124}
125
126void Session::serverError(QLocalSocket::LocalSocketError socketError)
127{
128 if (socketError == QLocalSocket::PeerClosedError) {
129 QCoreApplication::exit(0);
130 return;
131 }
132
133 std::cerr << qPrintable(m_session->errorString());
134 QCoreApplication::exit(1);
135}
136
137void Session::serverRead()
138{
139 QByteArray buffer(1024, Qt::Uninitialized);
140 qint64 readSize = 0;
141
142 while ((readSize = m_session->read(buffer.data(), buffer.size())) > 0) {
143 write(1, buffer.data(), readSize);
144 m_receivedBytes += readSize;
145 }
146}
147
148void Session::printStats() const
149{
150 std::cerr << "Connection time: " << m_connectionTime.elapsed() << " ms" << std::endl;
151 std::cerr << "Sent: " << m_sentBytes << " bytes" << std::endl;
152 std::cerr << "Received: " << m_receivedBytes << " bytes" << std::endl;
153}
154