1/*
2 Copyright (C) 2006-2007 KovoKs <info@kovoks.nl>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20// Uncomment the next line for full comm debug
21// #define comm_debug
22
23// Own
24#include "socket.h"
25
26// Qt
27#include <QByteArray>
28#include <QSslSocket>
29
30// KDE
31#include <KDebug>
32#include <ksocketfactory.h>
33
34using namespace MailTransport;
35
36namespace MailTransport {
37
38class SocketPrivate
39{
40 public:
41 SocketPrivate( Socket *s );
42 Socket *const q;
43 QSslSocket *socket;
44 QString server;
45 QString protocol;
46 int port;
47 bool secure;
48
49 // slots
50 void slotConnected();
51 void slotStateChanged( QAbstractSocket::SocketState state );
52 void slotModeChanged( QSslSocket::SslMode state );
53 void slotSocketRead();
54 void slotSslErrors( const QList<QSslError> &errors );
55
56 private:
57 QString m_msg;
58};
59
60}
61
62SocketPrivate::SocketPrivate( Socket *s ) : q( s )
63{
64}
65
66void SocketPrivate::slotConnected()
67{
68 kDebug();
69
70 if ( !secure ) {
71 kDebug() << "normal connect";
72 emit q->connected();
73 } else {
74 kDebug() << "encrypted connect";
75 socket->startClientEncryption();
76 }
77}
78
79void SocketPrivate::slotStateChanged( QAbstractSocket::SocketState state )
80{
81#ifdef comm_debug
82 kDebug() << "State is now:" << ( int ) state;
83#endif
84 if ( state == QAbstractSocket::UnconnectedState ) {
85 emit q->failed();
86 }
87}
88
89void SocketPrivate::slotModeChanged( QSslSocket::SslMode state )
90{
91#ifdef comm_debug
92 kDebug() << "Mode is now:" << state;
93#endif
94 if ( state == QSslSocket::SslClientMode ) {
95 emit q->tlsDone();
96 }
97}
98
99void SocketPrivate::slotSocketRead()
100{
101 kDebug();
102
103 if ( !socket ) {
104 return;
105 }
106
107 m_msg += QLatin1String( socket->readAll() );
108
109 if ( !m_msg.endsWith( QLatin1Char( '\n' ) ) ) {
110 return;
111 }
112
113#ifdef comm_debug
114 kDebug() << socket->isEncrypted() << m_msg.trimmed();
115#endif
116
117 emit q->data( m_msg );
118 m_msg.clear();
119}
120
121void SocketPrivate::slotSslErrors( const QList<QSslError> & )
122{
123 kDebug();
124 /* We can safely ignore the errors, we are only interested in the
125 capabilities. We're not sending auth info. */
126 socket->ignoreSslErrors();
127 emit q->connected();
128}
129
130// ------------------ end private ---------------------------//
131
132Socket::Socket( QObject *parent )
133 : QObject( parent ), d( new SocketPrivate( this ) )
134{
135 d->socket = 0;
136 d->port = 0;
137 d->secure = false;
138 kDebug();
139}
140
141Socket::~Socket()
142{
143 kDebug();
144 delete d;
145}
146
147void Socket::reconnect()
148{
149 kDebug() << "Connecting to:" << d->server << ":" << d->port;
150
151#ifdef comm_debug
152 // kDebug() << d->protocol;
153#endif
154
155 if ( d->socket ) {
156 return;
157 }
158
159 d->socket =
160 static_cast<QSslSocket *>( KSocketFactory::connectToHost( d->protocol, d->server,
161 d->port, this ) );
162
163 d->socket->setProtocol( QSsl::AnyProtocol );
164
165 connect( d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
166 SLOT(slotStateChanged(QAbstractSocket::SocketState)) );
167 connect( d->socket, SIGNAL(modeChanged(QSslSocket::SslMode)),
168 SLOT(slotModeChanged(QSslSocket::SslMode)) );
169 connect( d->socket, SIGNAL(connected()), SLOT(slotConnected()) );
170 connect( d->socket, SIGNAL(readyRead()), SLOT(slotSocketRead()) );
171 connect( d->socket, SIGNAL(encrypted()), SIGNAL(connected()) );
172 connect( d->socket, SIGNAL(sslErrors(QList<QSslError>)),
173 SLOT(slotSslErrors(QList<QSslError>)) );
174}
175
176void Socket::write( const QString &text )
177{
178 // kDebug();
179 // Eat things in the queue when there is no connection. We need
180 // to get a connection first don't we...
181 if ( !d->socket || !available() ) {
182 return;
183 }
184
185 QByteArray cs = ( text + QLatin1String( "\r\n" ) ).toLatin1();
186
187#ifdef comm_debug
188 kDebug() << "C :" << cs;
189#endif
190
191 d->socket->write( cs.data(), cs.size() );
192}
193
194bool Socket::available()
195{
196 // kDebug();
197 bool ok = d->socket && d->socket->state() == QAbstractSocket::ConnectedState;
198 return ok;
199}
200
201void Socket::startTLS()
202{
203 kDebug() << objectName();
204 d->socket->setProtocol( QSsl::TlsV1 );
205 d->socket->startClientEncryption();
206}
207
208void Socket::setProtocol( const QString &proto )
209{
210 d->protocol = proto;
211}
212
213void Socket::setServer( const QString &server )
214{
215 d->server = server;
216}
217
218void Socket::setPort( int port )
219{
220 d->port = port;
221}
222
223void Socket::setSecure( bool what )
224{
225 d->secure = what;
226}
227
228#include "moc_socket.cpp"
229