summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/transferserver.cpp4
1 files changed, 3 insertions, 1 deletions
diff --git a/core/launcher/transferserver.cpp b/core/launcher/transferserver.cpp
index eea9f3a..9519d11 100644
--- a/core/launcher/transferserver.cpp
+++ b/core/launcher/transferserver.cpp
@@ -1,732 +1,734 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of the Qtopia Environment. 4** This file is part of the Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20//#define _XOPEN_SOURCE 20//#define _XOPEN_SOURCE
21 21
22#include <qtopia/global.h> 22#include <qtopia/global.h>
23#include <qtopia/qpeapplication.h> 23#include <qtopia/qpeapplication.h>
24 24
25#ifndef Q_OS_WIN32 25#ifndef Q_OS_WIN32
26#include <pwd.h> 26#include <pwd.h>
27#include <sys/types.h> 27#include <sys/types.h>
28#include <unistd.h> 28#include <unistd.h>
29#include <stdlib.h> 29#include <stdlib.h>
30#include <time.h> 30#include <time.h>
31 31
32#ifndef Q_OS_MACX 32#ifndef Q_OS_MACX
33#include <shadow.h> 33#include <shadow.h>
34#include <crypt.h> 34#include <crypt.h>
35#endif /* Q_OS_MACX */ 35#endif /* Q_OS_MACX */
36 36
37#else 37#else
38#include <stdlib.h> 38#include <stdlib.h>
39#include <time.h> 39#include <time.h>
40#endif 40#endif
41 41
42 42
43#if defined(_OS_LINUX_) 43#if defined(_OS_LINUX_)
44#include <shadow.h> 44#include <shadow.h>
45#endif 45#endif
46 46
47#include <qdir.h> 47#include <qdir.h>
48#include <qfile.h> 48#include <qfile.h>
49#include <qtextstream.h> 49#include <qtextstream.h>
50#include <qdatastream.h> 50#include <qdatastream.h>
51#include <qmessagebox.h> 51#include <qmessagebox.h>
52#include <qstringlist.h> 52#include <qstringlist.h>
53#include <qfileinfo.h> 53#include <qfileinfo.h>
54#include <qregexp.h> 54#include <qregexp.h>
55//#include <qtopia/qcopchannel_qws.h> 55//#include <qtopia/qcopchannel_qws.h>
56#include <qtopia/process.h> 56#include <qtopia/process.h>
57#include <qtopia/global.h> 57#include <qtopia/global.h>
58#include <qtopia/config.h> 58#include <qtopia/config.h>
59#include <qtopia/private/contact.h> 59#include <qtopia/private/contact.h>
60#include <qtopia/quuid.h> 60#include <qtopia/quuid.h>
61#include <qtopia/version.h> 61#include <qtopia/version.h>
62#ifdef Q_WS_QWS 62#ifdef Q_WS_QWS
63#include <qtopia/qcopenvelope_qws.h> 63#include <qtopia/qcopenvelope_qws.h>
64#endif 64#endif
65 65
66#include "launcherglobal.h" 66#include "launcherglobal.h"
67 67
68#include "transferserver.h" 68#include "transferserver.h"
69#include <qtopia/qprocess.h> 69#include <qtopia/qprocess.h>
70 70
71const int block_size = 51200; 71const int block_size = 51200;
72 72
73TransferServer::TransferServer( Q_UINT16 port, QObject *parent, 73TransferServer::TransferServer( Q_UINT16 port, QObject *parent,
74 const char* name) 74 const char* name)
75 : QServerSocket( port, 1, parent, name ) 75 : QServerSocket( port, 1, parent, name )
76{ 76{
77 connections.setAutoDelete( TRUE ); 77 connections.setAutoDelete( TRUE );
78 if ( !ok() ) 78 if ( !ok() )
79 qWarning( "Failed to bind to port %d", port ); 79 qWarning( "Failed to bind to port %d", port );
80} 80}
81 81
82void TransferServer::authorizeConnections() 82void TransferServer::authorizeConnections()
83{ 83{
84 QListIterator<ServerPI> it(connections); 84 QListIterator<ServerPI> it(connections);
85 while ( it.current() ) { 85 while ( it.current() ) {
86 if ( !it.current()->verifyAuthorised() ) { 86 if ( !it.current()->verifyAuthorised() ) {
87 disconnect( it.current(), SIGNAL(connectionClosed(ServerPI *)), this, SLOT( closed(ServerPI *)) ); 87 disconnect( it.current(), SIGNAL(connectionClosed(ServerPI *)), this, SLOT( closed(ServerPI *)) );
88 connections.removeRef( it.current() ); 88 connections.removeRef( it.current() );
89 } else 89 } else
90 ++it; 90 ++it;
91 } 91 }
92} 92}
93 93
94void TransferServer::closed(ServerPI *item) 94void TransferServer::closed(ServerPI *item)
95{ 95{
96 connections.removeRef(item); 96 connections.removeRef(item);
97} 97}
98 98
99TransferServer::~TransferServer() 99TransferServer::~TransferServer()
100{ 100{
101} 101}
102 102
103void TransferServer::newConnection( int socket ) 103void TransferServer::newConnection( int socket )
104{ 104{
105 ServerPI *ptr = new ServerPI( socket, this ); 105 ServerPI *ptr = new ServerPI( socket, this );
106 connect( ptr, SIGNAL(connectionClosed(ServerPI *)), this, SLOT( closed(ServerPI *)) ); 106 connect( ptr, SIGNAL(connectionClosed(ServerPI *)), this, SLOT( closed(ServerPI *)) );
107 connections.append( ptr ); 107 connections.append( ptr );
108} 108}
109 109
110QString SyncAuthentication::serverId() 110QString SyncAuthentication::serverId()
111{ 111{
112 Config cfg("Security"); 112 Config cfg("Security");
113 cfg.setGroup("Sync"); 113 cfg.setGroup("Sync");
114 QString r = cfg.readEntry("serverid"); 114 QString r = cfg.readEntry("serverid");
115 115
116 if ( r.isEmpty() ) { 116 if ( r.isEmpty() ) {
117 r = Opie::Global::uuid(); 117 r = Opie::Global::uuid();
118 cfg.writeEntry("serverid", r ); 118 cfg.writeEntry("serverid", r );
119 } 119 }
120 return r; 120 return r;
121} 121}
122 122
123QString SyncAuthentication::ownerName() 123QString SyncAuthentication::ownerName()
124{ 124{
125 QString vfilename = Global::applicationFileName("addressbook", 125 QString vfilename = Global::applicationFileName("addressbook",
126 "businesscard.vcf"); 126 "businesscard.vcf");
127 if (QFile::exists(vfilename)) { 127 if (QFile::exists(vfilename)) {
128 Contact c; 128 Contact c;
129 c = Contact::readVCard( vfilename )[0]; 129 c = Contact::readVCard( vfilename )[0];
130 return c.fullName(); 130 return c.fullName();
131 } 131 }
132 132
133 return QString::null; 133 return QString::null;
134} 134}
135 135
136QString SyncAuthentication::loginName() 136QString SyncAuthentication::loginName()
137{ 137{
138 struct passwd *pw = 0L; 138 struct passwd *pw = 0L;
139#ifndef Q_OS_WIN32 139#ifndef Q_OS_WIN32
140 pw = getpwuid( geteuid() ); 140 pw = getpwuid( geteuid() );
141 return QString::fromLocal8Bit( pw->pw_name ); 141 return QString::fromLocal8Bit( pw->pw_name );
142#else 142#else
143 //### revise 143 //### revise
144 return QString(); 144 return QString();
145#endif 145#endif
146} 146}
147 147
148int SyncAuthentication::isAuthorized(QHostAddress peeraddress) 148int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
149{ 149{
150 Config cfg("Security"); 150 Config cfg("Security");
151 cfg.setGroup("Sync"); 151 cfg.setGroup("Sync");
152 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); 152 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0");
153 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100); 153 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100);
154 154
155 // QHostAddress allowed; 155 // QHostAddress allowed;
156 // allowed.setAddress(allowedstr); 156 // allowed.setAddress(allowedstr);
157 // uint auth_peer = allowed.ip4Addr(); 157 // uint auth_peer = allowed.ip4Addr();
158 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24); 158 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24);
159 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined 159 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined
160 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits)); 160 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits));
161 161
162 return (peeraddress.ip4Addr() & mask) == auth_peer; 162 return (peeraddress.ip4Addr() & mask) == auth_peer;
163} 163}
164 164
165bool SyncAuthentication::checkUser( const QString& user ) 165bool SyncAuthentication::checkUser( const QString& user )
166{ 166{
167 if ( user.isEmpty() ) return FALSE; 167 if ( user.isEmpty() ) return FALSE;
168 QString euser = loginName(); 168 QString euser = loginName();
169 return user == euser; 169 return user == euser;
170} 170}
171 171
172bool SyncAuthentication::checkPassword( const QString& password ) 172bool SyncAuthentication::checkPassword( const QString& password )
173{ 173{
174#ifdef ALLOW_UNIX_USER_FTP 174#ifdef ALLOW_UNIX_USER_FTP
175 // First, check system password... 175 // First, check system password...
176 176
177 struct passwd *pw = 0; 177 struct passwd *pw = 0;
178 struct spwd *spw = 0; 178 struct spwd *spw = 0;
179 179
180 pw = getpwuid( geteuid() ); 180 pw = getpwuid( geteuid() );
181 spw = getspnam( pw->pw_name ); 181 spw = getspnam( pw->pw_name );
182 182
183 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); 183 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
184 if ( cpwd == "x" && spw ) 184 if ( cpwd == "x" && spw )
185 cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); 185 cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
186 186
187 // Note: some systems use more than crypt for passwords. 187 // Note: some systems use more than crypt for passwords.
188 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); 188 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
189 if ( cpwd == cpassword ) 189 if ( cpwd == cpassword )
190 return TRUE; 190 return TRUE;
191#endif 191#endif
192 192
193 static int lastdenial=0; 193 static int lastdenial=0;
194 static int denials=0; 194 static int denials=0;
195 int now = time(0); 195 int now = time(0);
196 196
197 Config cfg("Security"); 197 Config cfg("Security");
198 cfg.setGroup("Sync"); 198 cfg.setGroup("Sync");
199 QString syncapp = cfg.readEntry("syncapp","Qtopia"); 199 QString syncapp = cfg.readEntry("syncapp","Qtopia");
200 200
201 //No password needed if the user really wants it 201 //No password needed if the user really wants it
202 if (syncapp == "IntelliSync") { 202 if (syncapp == "IntelliSync") {
203 return TRUE; 203 return TRUE;
204 } 204 }
205 205
206 // Detect old Qtopia Desktop (no password) 206 // Detect old Qtopia Desktop (no password)
207 if ( password.isEmpty() ) { 207 if ( password.isEmpty() ) {
208 if ( denials < 3 || now > lastdenial+600 ) { 208 if ( denials < 3 || now > lastdenial+600 ) {
209 QMessageBox unauth( 209 QMessageBox unauth(
210 tr("Sync Connection"), 210 tr("Sync Connection"),
211 tr("<p>An unauthorized system is requesting access to this device." 211 tr("<p>An unauthorized system is requesting access to this device."
212 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " 212 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, "
213 "please upgrade or change the security setting to use IntelliSync." ), 213 "please upgrade or change the security setting to use IntelliSync." ),
214 QMessageBox::Warning, 214 QMessageBox::Warning,
215 QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton, 215 QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton,
216 0, QString::null, TRUE, WStyle_StaysOnTop); 216 0, QString::null, TRUE, WStyle_StaysOnTop);
217 unauth.setButtonText(QMessageBox::Cancel, tr("Deny")); 217 unauth.setButtonText(QMessageBox::Cancel, tr("Deny"));
218 unauth.exec(); 218 unauth.exec();
219 219
220 denials++; 220 denials++;
221 lastdenial=now; 221 lastdenial=now;
222 } 222 }
223 return FALSE; 223 return FALSE;
224 224
225 } 225 }
226 226
227 // Second, check sync password... 227 // Second, check sync password...
228 228
229 static int lock=0; 229 static int lock=0;
230 if ( lock ) return FALSE; 230 if ( lock ) return FALSE;
231 231
232 ++lock; 232 ++lock;
233 233
234 /* 234 /*
235 * we need to support old Sync software and QtopiaDesktop 235 * we need to support old Sync software and QtopiaDesktop
236 */ 236 */
237 if ( password.left(6) == "Qtopia" || password.left(6) == "rootme" ) { 237 if ( password.left(6) == "Qtopia" || password.left(6) == "rootme" ) {
238 Config cfg( "Security" ); 238 Config cfg( "Security" );
239 cfg.setGroup("Sync"); 239 cfg.setGroup("Sync");
240 QStringList pwds = cfg.readListEntry("Passwords",' '); 240 QStringList pwds = cfg.readListEntry("Passwords",' ');
241 for (QStringList::ConstIterator it=pwds.begin(); it!=pwds.end(); ++it) { 241 for (QStringList::ConstIterator it=pwds.begin(); it!=pwds.end(); ++it) {
242#ifndef Q_OS_WIN32 242#ifndef Q_OS_WIN32
243 QString cpassword = QString::fromLocal8Bit( 243 QString cpassword = QString::fromLocal8Bit(
244 crypt( password.mid(8).local8Bit(), (*it).left(2).latin1() ) ); 244 crypt( password.mid(8).local8Bit(), (*it).left(2).latin1() ) );
245#else 245#else
246 // ### revise 246 // ### revise
247 QString cpassword(""); 247 QString cpassword("");
248#endif 248#endif
249 if ( *it == cpassword ) { 249 if ( *it == cpassword ) {
250 lock--; 250 lock--;
251 return TRUE; 251 return TRUE;
252 } 252 }
253 } 253 }
254 254
255 // Unrecognized system. Be careful... 255 // Unrecognized system. Be careful...
256 QMessageBox unrecbox( 256 QMessageBox unrecbox(
257 tr("Sync Connection"), 257 tr("Sync Connection"),
258 tr("<p>An unrecognized system is requesting access to this device." 258 tr("<p>An unrecognized system is requesting access to this device."
259 "<p>If you have just initiated a Sync for the first time, this is normal."), 259 "<p>If you have just initiated a Sync for the first time, this is normal."),
260 QMessageBox::Warning, 260 QMessageBox::Warning,
261 QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::NoButton, 261 QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::NoButton,
262 0, QString::null, TRUE, WStyle_StaysOnTop); 262 0, QString::null, TRUE, WStyle_StaysOnTop);
263 unrecbox.setButtonText(QMessageBox::Cancel, tr("Deny")); 263 unrecbox.setButtonText(QMessageBox::Cancel, tr("Deny"));
264 unrecbox.setButtonText(QMessageBox::Yes, tr("Allow")); 264 unrecbox.setButtonText(QMessageBox::Yes, tr("Allow"));
265 265
266 if ( (denials > 2 && now < lastdenial+600) 266 if ( (denials > 2 && now < lastdenial+600)
267 || unrecbox.exec() != QMessageBox::Yes) 267 || unrecbox.exec() != QMessageBox::Yes)
268 { 268 {
269 denials++; 269 denials++;
270 lastdenial=now; 270 lastdenial=now;
271 lock--; 271 lock--;
272 return FALSE; 272 return FALSE;
273 } else { 273 } else {
274 const char salty[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."; 274 const char salty[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.";
275 char salt[2]; 275 char salt[2];
276 salt[0]= salty[rand() % (sizeof(salty)-1)]; 276 salt[0]= salty[rand() % (sizeof(salty)-1)];
277 salt[1]= salty[rand() % (sizeof(salty)-1)]; 277 salt[1]= salty[rand() % (sizeof(salty)-1)];
278#ifndef Q_OS_WIN32 278#ifndef Q_OS_WIN32
279 QString cpassword = QString::fromLocal8Bit( 279 QString cpassword = QString::fromLocal8Bit(
280 crypt( password.mid(8).local8Bit(), salt ) ); 280 crypt( password.mid(8).local8Bit(), salt ) );
281#else 281#else
282 //### revise 282 //### revise
283 QString cpassword(""); 283 QString cpassword("");
284#endif 284#endif
285 denials=0; 285 denials=0;
286 pwds.prepend(cpassword); 286 pwds.prepend(cpassword);
287 cfg.writeEntry("Passwords",pwds,' '); 287 cfg.writeEntry("Passwords",pwds,' ');
288 lock--; 288 lock--;
289 return TRUE; 289 return TRUE;
290 } 290 }
291 } 291 }
292 lock--; 292 lock--;
293 293
294 return FALSE; 294 return FALSE;
295} 295}
296 296
297 297
298ServerPI::ServerPI( int socket, QObject *parent, const char* name ) 298ServerPI::ServerPI( int socket, QObject *parent, const char* name )
299 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ), 299 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ),
300 storFileSize(-1) 300 storFileSize(-1)
301{ 301{
302 state = Connected; 302 state = Connected;
303 303
304 setSocket( socket ); 304 setSocket( socket );
305 305
306 peerport = peerPort(); 306 peerport = peerPort();
307 peeraddress = peerAddress(); 307 peeraddress = peerAddress();
308 308
309#ifndef INSECURE 309#ifndef INSECURE
310 if ( !SyncAuthentication::isAuthorized(peeraddress) ) { 310 if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
311 state = Forbidden; 311 state = Forbidden;
312 startTimer( 0 ); 312 startTimer( 0 );
313 } else 313 } else
314#endif 314#endif
315 { 315 {
316 connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); 316 connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
317 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); 317 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
318 318
319 passiv = FALSE; 319 passiv = FALSE;
320 for( int i = 0; i < 4; i++ ) 320 for( int i = 0; i < 4; i++ )
321 wait[i] = FALSE; 321 wait[i] = FALSE;
322 322
323 send( "220 Qtopia " QPE_VERSION " FTP Server" ); // No tr 323 send( "220 Qtopia " QPE_VERSION " FTP Server" ); // No tr
324 state = Wait_USER; 324 state = Wait_USER;
325 325
326 dtp = new ServerDTP( this ); 326 dtp = new ServerDTP( this );
327 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); 327 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
328 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); 328 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
329 connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) ); 329 connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) );
330 330
331 331
332 directory = QDir::currentDirPath(); 332 directory = QDir::currentDirPath();
333 333
334 static int p = 1024; 334 static int p = 1024;
335 335
336 while ( !serversocket || !serversocket->ok() ) { 336 while ( !serversocket || !serversocket->ok() ) {
337 delete serversocket; 337 delete serversocket;
338 serversocket = new ServerSocket( ++p, this ); 338 serversocket = new ServerSocket( ++p, this );
339 } 339 }
340 connect( serversocket, SIGNAL( newIncomming( int ) ), 340 connect( serversocket, SIGNAL( newIncomming( int ) ),
341 SLOT( newConnection( int ) ) ); 341 SLOT( newConnection( int ) ) );
342 } 342 }
343} 343}
344 344
345ServerPI::~ServerPI() 345ServerPI::~ServerPI()
346{ 346{
347 close(); 347 close();
348 dtp->close(); 348
349 if ( dtp )
350 dtp->close();
349 delete dtp; 351 delete dtp;
350 delete serversocket; 352 delete serversocket;
351} 353}
352 354
353bool ServerPI::verifyAuthorised() 355bool ServerPI::verifyAuthorised()
354{ 356{
355 if ( !SyncAuthentication::isAuthorized(peerAddress()) ) { 357 if ( !SyncAuthentication::isAuthorized(peerAddress()) ) {
356 state = Forbidden; 358 state = Forbidden;
357 return FALSE; 359 return FALSE;
358 } 360 }
359 return TRUE; 361 return TRUE;
360} 362}
361 363
362void ServerPI::connectionClosed() 364void ServerPI::connectionClosed()
363{ 365{
364 // qDebug( "Debug: Connection closed" ); 366 // qDebug( "Debug: Connection closed" );
365 emit connectionClosed(this); 367 emit connectionClosed(this);
366} 368}
367 369
368void ServerPI::send( const QString& msg ) 370void ServerPI::send( const QString& msg )
369{ 371{
370 QTextStream os( this ); 372 QTextStream os( this );
371 os << msg << endl; 373 os << msg << endl;
372 //qDebug( "Reply: %s", msg.latin1() ); 374 //qDebug( "Reply: %s", msg.latin1() );
373} 375}
374 376
375void ServerPI::read() 377void ServerPI::read()
376{ 378{
377 while ( canReadLine() ) 379 while ( canReadLine() )
378 process( readLine().stripWhiteSpace() ); 380 process( readLine().stripWhiteSpace() );
379} 381}
380 382
381bool ServerPI::checkReadFile( const QString& file ) 383bool ServerPI::checkReadFile( const QString& file )
382{ 384{
383 QString filename; 385 QString filename;
384 386
385 if ( file[0] != "/" ) 387 if ( file[0] != "/" )
386 filename = directory.path() + "/" + file; 388 filename = directory.path() + "/" + file;
387 else 389 else
388 filename = file; 390 filename = file;
389 391
390 QFileInfo fi( filename ); 392 QFileInfo fi( filename );
391 return ( fi.exists() && fi.isReadable() ); 393 return ( fi.exists() && fi.isReadable() );
392} 394}
393 395
394bool ServerPI::checkWriteFile( const QString& file ) 396bool ServerPI::checkWriteFile( const QString& file )
395{ 397{
396 QString filename; 398 QString filename;
397 399
398 if ( file[0] != "/" ) 400 if ( file[0] != "/" )
399 filename = directory.path() + "/" + file; 401 filename = directory.path() + "/" + file;
400 else 402 else
401 filename = file; 403 filename = file;
402 404
403 QFileInfo fi( filename ); 405 QFileInfo fi( filename );
404 406
405 if ( fi.exists() ) 407 if ( fi.exists() )
406 if ( !QFile( filename ).remove() ) 408 if ( !QFile( filename ).remove() )
407 return FALSE; 409 return FALSE;
408 return TRUE; 410 return TRUE;
409} 411}
410 412
411void ServerPI::process( const QString& message ) 413void ServerPI::process( const QString& message )
412{ 414{
413 //qDebug( "Command: %s", message.latin1() ); 415 //qDebug( "Command: %s", message.latin1() );
414 416
415 // split message using "," as separator 417 // split message using "," as separator
416 QStringList msg = QStringList::split( " ", message ); 418 QStringList msg = QStringList::split( " ", message );
417 if ( msg.isEmpty() ) return; 419 if ( msg.isEmpty() ) return;
418 420
419 // command token 421 // command token
420 QString cmd = msg[0].upper(); 422 QString cmd = msg[0].upper();
421 423
422 // argument token 424 // argument token
423 QString arg; 425 QString arg;
424 if ( msg.count() >= 2 ) 426 if ( msg.count() >= 2 )
425 arg = msg[1]; 427 arg = msg[1];
426 428
427 // full argument string 429 // full argument string
428 QString args; 430 QString args;
429 if ( msg.count() >= 2 ) { 431 if ( msg.count() >= 2 ) {
430 QStringList copy( msg ); 432 QStringList copy( msg );
431 // FIXME: for Qt3 433 // FIXME: for Qt3
432 // copy.pop_front() 434 // copy.pop_front()
433 copy.remove( copy.begin() ); 435 copy.remove( copy.begin() );
434 args = copy.join( " " ); 436 args = copy.join( " " );
435 } 437 }
436 438
437 //qDebug( "args: %s", args.latin1() ); 439 //qDebug( "args: %s", args.latin1() );
438 440
439 // we always respond to QUIT, regardless of state 441 // we always respond to QUIT, regardless of state
440 if ( cmd == "QUIT" ) { 442 if ( cmd == "QUIT" ) {
441 send( "211 Good bye!" ); // No tr 443 send( "211 Good bye!" ); // No tr
442 close(); 444 close();
443 return; 445 return;
444 } 446 }
445 447
446 // connected to client 448 // connected to client
447 if ( Connected == state ) 449 if ( Connected == state )
448 return; 450 return;
449 451
450 // waiting for user name 452 // waiting for user name
451 if ( Wait_USER == state ) { 453 if ( Wait_USER == state ) {
452 454
453 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { 455 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
454 send( "530 Please login with USER and PASS" ); // No tr 456 send( "530 Please login with USER and PASS" ); // No tr
455 return; 457 return;
456 } 458 }
457 send( "331 User name ok, need password" ); // No tr 459 send( "331 User name ok, need password" ); // No tr
458 state = Wait_PASS; 460 state = Wait_PASS;
459 return; 461 return;
460 } 462 }
461 463
462 // waiting for password 464 // waiting for password
463 if ( Wait_PASS == state ) { 465 if ( Wait_PASS == state ) {
464 466
465 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { 467 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
466 send( "530 Please login with USER and PASS" ); // No tr 468 send( "530 Please login with USER and PASS" ); // No tr
467 return; 469 return;
468 } 470 }
469 send( "230 User logged in, proceed" ); // No tr 471 send( "230 User logged in, proceed" ); // No tr
470 state = Ready; 472 state = Ready;
471 return; 473 return;
472 } 474 }
473 475
474 // ACCESS CONTROL COMMANDS 476 // ACCESS CONTROL COMMANDS
475 477
476 // Only an ALLO sent immediately before STOR is valid. 478 // Only an ALLO sent immediately before STOR is valid.
477 if ( cmd != "STOR" ) 479 if ( cmd != "STOR" )
478 storFileSize = -1; 480 storFileSize = -1;
479 481
480 // account (ACCT) 482 // account (ACCT)
481 if ( cmd == "ACCT" ) { 483 if ( cmd == "ACCT" ) {
482 // even wu-ftp does not support it 484 // even wu-ftp does not support it
483 send( "502 Command not implemented" ); // No tr 485 send( "502 Command not implemented" ); // No tr
484 } 486 }
485 487
486 // change working directory (CWD) 488 // change working directory (CWD)
487 else if ( cmd == "CWD" ) { 489 else if ( cmd == "CWD" ) {
488 490
489 if ( !args.isEmpty() ) { 491 if ( !args.isEmpty() ) {
490 if ( directory.cd( args, TRUE ) ) 492 if ( directory.cd( args, TRUE ) )
491 send( "250 Requested file action okay, completed" ); // No tr 493 send( "250 Requested file action okay, completed" ); // No tr
492 else 494 else
493 send( "550 Requested action not taken" ); // No tr 495 send( "550 Requested action not taken" ); // No tr
494 } 496 }
495 else 497 else
496 send( "500 Syntax error, command unrecognized" ); // No tr 498 send( "500 Syntax error, command unrecognized" ); // No tr
497 } 499 }
498 500
499 // change to parent directory (CDUP) 501 // change to parent directory (CDUP)
500 else if ( cmd == "CDUP" ) { 502 else if ( cmd == "CDUP" ) {
501 if ( directory.cdUp() ) 503 if ( directory.cdUp() )
502 send( "250 Requested file action okay, completed" ); // No tr 504 send( "250 Requested file action okay, completed" ); // No tr
503 else 505 else
504 send( "550 Requested action not taken" ); // No tr 506 send( "550 Requested action not taken" ); // No tr
505 } 507 }
506 508
507 // structure mount (SMNT) 509 // structure mount (SMNT)
508 else if ( cmd == "SMNT" ) { 510 else if ( cmd == "SMNT" ) {
509 // even wu-ftp does not support it 511 // even wu-ftp does not support it
510 send( "502 Command not implemented" ); // No tr 512 send( "502 Command not implemented" ); // No tr
511 } 513 }
512 514
513 // reinitialize (REIN) 515 // reinitialize (REIN)
514 else if ( cmd == "REIN" ) { 516 else if ( cmd == "REIN" ) {
515 // even wu-ftp does not support it 517 // even wu-ftp does not support it
516 send( "502 Command not implemented" ); // No tr 518 send( "502 Command not implemented" ); // No tr
517 } 519 }
518 520
519 521
520 // TRANSFER PARAMETER COMMANDS 522 // TRANSFER PARAMETER COMMANDS
521 523
522 524
523 // data port (PORT) 525 // data port (PORT)
524 else if ( cmd == "PORT" ) { 526 else if ( cmd == "PORT" ) {
525 if ( parsePort( arg ) ) 527 if ( parsePort( arg ) )
526 send( "200 Command okay" ); // No tr 528 send( "200 Command okay" ); // No tr
527 else 529 else
528 send( "500 Syntax error, command unrecognized" ); // No tr 530 send( "500 Syntax error, command unrecognized" ); // No tr
529 } 531 }
530 532
531 // passive (PASV) 533 // passive (PASV)
532 else if ( cmd == "PASV" ) { 534 else if ( cmd == "PASV" ) {
533 passiv = TRUE; 535 passiv = TRUE;
534 send( "227 Entering Passive Mode (" // No tr 536 send( "227 Entering Passive Mode (" // No tr
535 + address().toString().replace( QRegExp( "\\." ), "," ) + "," 537 + address().toString().replace( QRegExp( "\\." ), "," ) + ","
536 + QString::number( ( serversocket->port() ) >> 8 ) + "," 538 + QString::number( ( serversocket->port() ) >> 8 ) + ","
537 + QString::number( ( serversocket->port() ) & 0xFF ) +")" ); 539 + QString::number( ( serversocket->port() ) & 0xFF ) +")" );
538 } 540 }
539 541
540 // representation type (TYPE) 542 // representation type (TYPE)
541 else if ( cmd == "TYPE" ) { 543 else if ( cmd == "TYPE" ) {
542 if ( arg.upper() == "A" || arg.upper() == "I" ) 544 if ( arg.upper() == "A" || arg.upper() == "I" )
543 send( "200 Command okay" ); // No tr 545 send( "200 Command okay" ); // No tr
544 else 546 else
545 send( "504 Command not implemented for that parameter" ); // No tr 547 send( "504 Command not implemented for that parameter" ); // No tr
546 } 548 }
547 549
548 // file structure (STRU) 550 // file structure (STRU)
549 else if ( cmd == "STRU" ) { 551 else if ( cmd == "STRU" ) {
550 if ( arg.upper() == "F" ) 552 if ( arg.upper() == "F" )
551 send( "200 Command okay" ); // No tr 553 send( "200 Command okay" ); // No tr
552 else 554 else
553 send( "504 Command not implemented for that parameter" ); // No tr 555 send( "504 Command not implemented for that parameter" ); // No tr
554 } 556 }
555 557
556 // transfer mode (MODE) 558 // transfer mode (MODE)
557 else if ( cmd == "MODE" ) { 559 else if ( cmd == "MODE" ) {
558 if ( arg.upper() == "S" ) 560 if ( arg.upper() == "S" )
559 send( "200 Command okay" ); // No tr 561 send( "200 Command okay" ); // No tr
560 else 562 else
561 send( "504 Command not implemented for that parameter" ); // No tr 563 send( "504 Command not implemented for that parameter" ); // No tr
562 } 564 }
563 565
564 566
565 // FTP SERVICE COMMANDS 567 // FTP SERVICE COMMANDS
566 568
567 569
568 // retrieve (RETR) 570 // retrieve (RETR)
569 else if ( cmd == "RETR" ) 571 else if ( cmd == "RETR" )
570 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) ) 572 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
571 || backupRestoreGzip( absFilePath( args ) ) ) { 573 || backupRestoreGzip( absFilePath( args ) ) ) {
572 send( "150 File status okay" ); // No tr 574 send( "150 File status okay" ); // No tr
573 sendFile( absFilePath( args ) ); 575 sendFile( absFilePath( args ) );
574 } 576 }
575 else { 577 else {
576 qDebug("550 Requested action not taken"); 578 qDebug("550 Requested action not taken");
577 send( "550 Requested action not taken" ); // No tr 579 send( "550 Requested action not taken" ); // No tr
578 } 580 }
579 581
580 // store (STOR) 582 // store (STOR)
581 else if ( cmd == "STOR" ) 583 else if ( cmd == "STOR" )
582 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) { 584 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
583 send( "150 File status okay" ); // No tr 585 send( "150 File status okay" ); // No tr
584 retrieveFile( absFilePath( args ) ); 586 retrieveFile( absFilePath( args ) );
585 } 587 }
586 else 588 else
587 send( "550 Requested action not taken" ); // No tr 589 send( "550 Requested action not taken" ); // No tr
588 590
589 // store unique (STOU) 591 // store unique (STOU)
590 else if ( cmd == "STOU" ) { 592 else if ( cmd == "STOU" ) {
591 send( "502 Command not implemented" ); // No tr 593 send( "502 Command not implemented" ); // No tr
592 } 594 }
593 595
594 // append (APPE) 596 // append (APPE)
595 else if ( cmd == "APPE" ) { 597 else if ( cmd == "APPE" ) {
596 send( "502 Command not implemented" ); // No tr 598 send( "502 Command not implemented" ); // No tr
597 } 599 }
598 600
599 // allocate (ALLO) 601 // allocate (ALLO)
600 else if ( cmd == "ALLO" ) { 602 else if ( cmd == "ALLO" ) {
601 storFileSize = args.toInt(); 603 storFileSize = args.toInt();
602 send( "200 Command okay" ); // No tr 604 send( "200 Command okay" ); // No tr
603 } 605 }
604 606
605 // restart (REST) 607 // restart (REST)
606 else if ( cmd == "REST" ) { 608 else if ( cmd == "REST" ) {
607 send( "502 Command not implemented" ); // No tr 609 send( "502 Command not implemented" ); // No tr
608 } 610 }
609 611
610 // rename from (RNFR) 612 // rename from (RNFR)
611 else if ( cmd == "RNFR" ) { 613 else if ( cmd == "RNFR" ) {
612 renameFrom = QString::null; 614 renameFrom = QString::null;
613 if ( args.isEmpty() ) 615 if ( args.isEmpty() )
614 send( "500 Syntax error, command unrecognized" ); // No tr 616 send( "500 Syntax error, command unrecognized" ); // No tr
615 else { 617 else {
616 QFile file( absFilePath( args ) ); 618 QFile file( absFilePath( args ) );
617 if ( file.exists() ) { 619 if ( file.exists() ) {
618 send( "350 File exists, ready for destination name" ); // No tr 620 send( "350 File exists, ready for destination name" ); // No tr
619 renameFrom = absFilePath( args ); 621 renameFrom = absFilePath( args );
620 } 622 }
621 else 623 else
622 send( "550 Requested action not taken" ); // No tr 624 send( "550 Requested action not taken" ); // No tr
623 } 625 }
624 } 626 }
625 627
626 // rename to (RNTO) 628 // rename to (RNTO)
627 else if ( cmd == "RNTO" ) { 629 else if ( cmd == "RNTO" ) {
628 if ( lastCommand != "RNFR" ) 630 if ( lastCommand != "RNFR" )
629 send( "503 Bad sequence of commands" ); // No tr 631 send( "503 Bad sequence of commands" ); // No tr
630 else if ( args.isEmpty() ) 632 else if ( args.isEmpty() )
631 send( "500 Syntax error, command unrecognized" ); // No tr 633 send( "500 Syntax error, command unrecognized" ); // No tr
632 else { 634 else {
633 QDir dir( absFilePath( args ) ); 635 QDir dir( absFilePath( args ) );
634 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) ) 636 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
635 send( "250 Requested file action okay, completed." ); // No tr 637 send( "250 Requested file action okay, completed." ); // No tr
636 else 638 else
637 send( "550 Requested action not taken" ); // No tr 639 send( "550 Requested action not taken" ); // No tr
638 } 640 }
639 } 641 }
640 642
641 // abort (ABOR) 643 // abort (ABOR)
642 else if ( cmd.contains( "ABOR" ) ) { 644 else if ( cmd.contains( "ABOR" ) ) {
643 dtp->close(); 645 dtp->close();
644 if ( dtp->dtpMode() != ServerDTP::Idle ) 646 if ( dtp->dtpMode() != ServerDTP::Idle )
645 send( "426 Connection closed; transfer aborted" ); // No tr 647 send( "426 Connection closed; transfer aborted" ); // No tr
646 else 648 else
647 send( "226 Closing data connection" ); // No tr 649 send( "226 Closing data connection" ); // No tr
648 } 650 }
649 651
650 // delete (DELE) 652 // delete (DELE)
651 else if ( cmd == "DELE" ) { 653 else if ( cmd == "DELE" ) {
652 if ( args.isEmpty() ) 654 if ( args.isEmpty() )
653 send( "500 Syntax error, command unrecognized" ); // No tr 655 send( "500 Syntax error, command unrecognized" ); // No tr
654 else { 656 else {
655 QFile file( absFilePath( args ) ) ; 657 QFile file( absFilePath( args ) ) ;
656 if ( file.remove() ) { 658 if ( file.remove() ) {
657 send( "250 Requested file action okay, completed" ); // No tr 659 send( "250 Requested file action okay, completed" ); // No tr
658 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 660 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
659 e << file.name(); 661 e << file.name();
660 } else { 662 } else {
661 send( "550 Requested action not taken" ); // No tr 663 send( "550 Requested action not taken" ); // No tr
662 } 664 }
663 } 665 }
664 } 666 }
665 667
666 // remove directory (RMD) 668 // remove directory (RMD)
667 else if ( cmd == "RMD" ) { 669 else if ( cmd == "RMD" ) {
668 if ( args.isEmpty() ) 670 if ( args.isEmpty() )
669 send( "500 Syntax error, command unrecognized" ); // No tr 671 send( "500 Syntax error, command unrecognized" ); // No tr
670 else { 672 else {
671 QDir dir; 673 QDir dir;
672 if ( dir.rmdir( absFilePath( args ), TRUE ) ) 674 if ( dir.rmdir( absFilePath( args ), TRUE ) )
673 send( "250 Requested file action okay, completed" ); // No tr 675 send( "250 Requested file action okay, completed" ); // No tr
674 else 676 else
675 send( "550 Requested action not taken" ); // No tr 677 send( "550 Requested action not taken" ); // No tr
676 } 678 }
677 } 679 }
678 680
679 // make directory (MKD) 681 // make directory (MKD)
680 else if ( cmd == "MKD" ) { 682 else if ( cmd == "MKD" ) {
681 if ( args.isEmpty() ) { 683 if ( args.isEmpty() ) {
682 qDebug(" Error: no arg"); 684 qDebug(" Error: no arg");
683 send( "500 Syntax error, command unrecognized" ); // No tr 685 send( "500 Syntax error, command unrecognized" ); // No tr
684 } 686 }
685 else { 687 else {
686 QDir dir; 688 QDir dir;
687 if ( dir.mkdir( absFilePath( args ), TRUE ) ) 689 if ( dir.mkdir( absFilePath( args ), TRUE ) )
688 send( "250 Requested file action okay, completed." ); // No tr 690 send( "250 Requested file action okay, completed." ); // No tr
689 else 691 else
690 send( "550 Requested action not taken" ); // No tr 692 send( "550 Requested action not taken" ); // No tr
691 } 693 }
692 } 694 }
693 695
694 // print working directory (PWD) 696 // print working directory (PWD)
695 else if ( cmd == "PWD" ) { 697 else if ( cmd == "PWD" ) {
696 send( "257 \"" + directory.path() +"\"" ); 698 send( "257 \"" + directory.path() +"\"" );
697 } 699 }
698 700
699 // list (LIST) 701 // list (LIST)
700 else if ( cmd == "LIST" ) { 702 else if ( cmd == "LIST" ) {
701 if ( sendList( absFilePath( args ) ) ) 703 if ( sendList( absFilePath( args ) ) )
702 send( "150 File status okay" ); // No tr 704 send( "150 File status okay" ); // No tr
703 else 705 else
704 send( "500 Syntax error, command unrecognized" ); // No tr 706 send( "500 Syntax error, command unrecognized" ); // No tr
705 } 707 }
706 708
707 // size (SIZE) 709 // size (SIZE)
708 else if ( cmd == "SIZE" ) { 710 else if ( cmd == "SIZE" ) {
709 QString filePath = absFilePath( args ); 711 QString filePath = absFilePath( args );
710 QFileInfo fi( filePath ); 712 QFileInfo fi( filePath );
711 bool gzipfile = backupRestoreGzip( filePath ); 713 bool gzipfile = backupRestoreGzip( filePath );
712 if ( !fi.exists() && !gzipfile ) 714 if ( !fi.exists() && !gzipfile )
713 send( "500 Syntax error, command unrecognized" ); // No tr 715 send( "500 Syntax error, command unrecognized" ); // No tr
714 else { 716 else {
715 if ( !gzipfile ) 717 if ( !gzipfile )
716 send( "213 " + QString::number( fi.size() ) ); 718 send( "213 " + QString::number( fi.size() ) );
717 else { 719 else {
718 Process duproc( QString("du") ); 720 Process duproc( QString("du") );
719 duproc.addArgument("-s"); 721 duproc.addArgument("-s");
720 QString in, out; 722 QString in, out;
721 if ( !duproc.exec(in, out) ) { 723 if ( !duproc.exec(in, out) ) {
722 qDebug("du process failed; just sending back 1K"); 724 qDebug("du process failed; just sending back 1K");
723 send( "213 1024"); 725 send( "213 1024");
724 } 726 }
725 else { 727 else {
726 QString size = out.left( out.find("\t") ); 728 QString size = out.left( out.find("\t") );
727 int guess = size.toInt()/5; 729 int guess = size.toInt()/5;
728 if ( filePath.contains("doc") ) // No tr 730 if ( filePath.contains("doc") ) // No tr
729 guess *= 1000; 731 guess *= 1000;
730 qDebug("sending back gzip guess of %d", guess); 732 qDebug("sending back gzip guess of %d", guess);
731 send( "213 " + QString::number(guess) ); 733 send( "213 " + QString::number(guess) );
732 } 734 }