summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/transferserver.cpp10
1 files changed, 7 insertions, 3 deletions
diff --git a/core/launcher/transferserver.cpp b/core/launcher/transferserver.cpp
index 1d4ca40..2b2e435 100644
--- a/core/launcher/transferserver.cpp
+++ b/core/launcher/transferserver.cpp
@@ -1,955 +1,959 @@
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#include "transferserver.h" 20#include "transferserver.h"
21 21
22/* OPIE */ 22/* OPIE */
23#include <opie2/odebug.h> 23#include <opie2/odebug.h>
24#include <opie2/oglobal.h> 24#include <opie2/oglobal.h>
25#include <qtopia/qprocess.h> 25#include <qtopia/qprocess.h>
26#include <qtopia/process.h> 26#include <qtopia/process.h>
27#include <qtopia/private/contact.h> 27#include <qtopia/private/contact.h>
28#include <qtopia/version.h> 28#include <qtopia/version.h>
29#ifdef Q_WS_QWS 29#ifdef Q_WS_QWS
30#include <qtopia/qcopenvelope_qws.h> 30#include <qtopia/qcopenvelope_qws.h>
31#endif 31#endif
32using namespace Opie::Core; 32using namespace Opie::Core;
33 33
34/* QT */ 34/* QT */
35#include <qtextstream.h> 35#include <qtextstream.h>
36#include <qmessagebox.h> 36#include <qmessagebox.h>
37 37
38/* STD */ 38/* STD */
39#include <pwd.h> 39#include <pwd.h>
40#include <sys/types.h> 40#include <sys/types.h>
41#include <unistd.h> 41#include <unistd.h>
42#include <stdlib.h> 42#include <stdlib.h>
43#include <time.h> 43#include <time.h>
44 44
45#ifndef Q_OS_MACX 45#ifndef Q_OS_MACX
46#include <shadow.h> 46#include <shadow.h>
47#include <crypt.h> 47#include <crypt.h>
48#endif /* Q_OS_MACX */ 48#endif /* Q_OS_MACX */
49 49
50const int block_size = 51200; 50const int block_size = 51200;
51 51
52TransferServer::TransferServer( Q_UINT16 port, QObject *parent, 52TransferServer::TransferServer( Q_UINT16 port, QObject *parent,
53 const char* name) 53 const char* name)
54 : QServerSocket( port, 1, parent, name ) 54 : QServerSocket( port, 1, parent, name )
55{ 55{
56 connections.setAutoDelete( TRUE ); 56 connections.setAutoDelete( TRUE );
57 if ( !ok() ) 57 if ( !ok() )
58 owarn << "Failed to bind to port " << port << "" << oendl; 58 owarn << "Failed to bind to port " << port << "" << oendl;
59} 59}
60 60
61void TransferServer::authorizeConnections() 61void TransferServer::authorizeConnections()
62{ 62{
63 QListIterator<ServerPI> it(connections); 63 QListIterator<ServerPI> it(connections);
64 while ( it.current() ) { 64 while ( it.current() ) {
65 if ( !it.current()->verifyAuthorised() ) { 65 if ( !it.current()->verifyAuthorised() ) {
66 disconnect( it.current(), SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) ); 66 disconnect( it.current(), SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) );
67 connections.removeRef( it.current() ); 67 connections.removeRef( it.current() );
68 } else 68 } else
69 ++it; 69 ++it;
70 } 70 }
71} 71}
72 72
73void TransferServer::closed(ServerPI *item) 73void TransferServer::closed(ServerPI *item)
74{ 74{
75 connections.removeRef(item); 75 connections.removeRef(item);
76} 76}
77 77
78TransferServer::~TransferServer() 78TransferServer::~TransferServer()
79{ 79{
80} 80}
81 81
82void TransferServer::newConnection( int socket ) 82void TransferServer::newConnection( int socket )
83{ 83{
84 ServerPI *ptr = new ServerPI( socket, this ); 84 ServerPI *ptr = new ServerPI( socket, this );
85 connect( ptr, SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) ); 85 connect( ptr, SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) );
86 connections.append( ptr ); 86 connections.append( ptr );
87} 87}
88 88
89QString SyncAuthentication::serverId() 89QString SyncAuthentication::serverId()
90{ 90{
91 Config cfg("Security"); 91 Config cfg("Security");
92 cfg.setGroup("Sync"); 92 cfg.setGroup("Sync");
93 QString r = cfg.readEntry("serverid"); 93 QString r = cfg.readEntry("serverid");
94 94
95 if ( r.isEmpty() ) { 95 if ( r.isEmpty() ) {
96 r = OGlobal::generateUuid(); 96 r = OGlobal::generateUuid();
97 cfg.writeEntry("serverid", r ); 97 cfg.writeEntry("serverid", r );
98 } 98 }
99 return r; 99 return r;
100} 100}
101 101
102QString SyncAuthentication::ownerName() 102QString SyncAuthentication::ownerName()
103{ 103{
104 QString vfilename = Global::applicationFileName("addressbook", 104 QString vfilename = Global::applicationFileName("addressbook",
105 "businesscard.vcf"); 105 "businesscard.vcf");
106 if (QFile::exists(vfilename)) { 106 if (QFile::exists(vfilename)) {
107 Contact c; 107 Contact c;
108 c = Contact::readVCard( vfilename )[0]; 108 c = Contact::readVCard( vfilename )[0];
109 return c.fullName(); 109 return c.fullName();
110 } 110 }
111 111
112 return QString::null; 112 return QString::null;
113} 113}
114 114
115QString SyncAuthentication::loginName() 115QString SyncAuthentication::loginName()
116{ 116{
117 struct passwd *pw = 0L; 117 struct passwd *pw = 0L;
118#ifndef Q_OS_WIN32 118#ifndef Q_OS_WIN32
119 pw = getpwuid( geteuid() ); 119 pw = getpwuid( geteuid() );
120 return QString::fromLocal8Bit( pw->pw_name ); 120 return QString::fromLocal8Bit( pw->pw_name );
121#else 121#else
122 //### revise 122 //### revise
123 return QString(); 123 return QString();
124#endif 124#endif
125} 125}
126 126
127int SyncAuthentication::isAuthorized(QHostAddress peeraddress) 127int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
128{ 128{
129 Config cfg("Security"); 129 Config cfg("Security");
130 cfg.setGroup("Sync"); 130 cfg.setGroup("Sync");
131 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); 131 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0");
132 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100); 132 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100);
133 133
134 // QHostAddress allowed; 134 // QHostAddress allowed;
135 // allowed.setAddress(allowedstr); 135 // allowed.setAddress(allowedstr);
136 // uint auth_peer = allowed.ip4Addr(); 136 // uint auth_peer = allowed.ip4Addr();
137 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24); 137 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24);
138 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined 138 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined
139 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits)); 139 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits));
140 140
141 return (peeraddress.ip4Addr() & mask) == auth_peer; 141 return (peeraddress.ip4Addr() & mask) == auth_peer;
142} 142}
143 143
144bool SyncAuthentication::checkUser( const QString& user ) 144bool SyncAuthentication::checkUser( const QString& user )
145{ 145{
146 if ( user.isEmpty() ) return FALSE; 146 if ( user.isEmpty() ) return FALSE;
147 QString euser = loginName(); 147 QString euser = loginName();
148 return user == euser; 148 return user == euser;
149} 149}
150 150
151bool SyncAuthentication::checkPassword( const QString& password ) 151bool SyncAuthentication::checkPassword( const QString& password )
152{ 152{
153#ifdef ALLOW_UNIX_USER_FTP 153#ifdef ALLOW_UNIX_USER_FTP
154 // First, check system password... 154 // First, check system password...
155 155
156 struct passwd *pw = 0; 156 struct passwd *pw = 0;
157 struct spwd *spw = 0; 157 struct spwd *spw = 0;
158 158
159 pw = getpwuid( geteuid() ); 159 pw = getpwuid( geteuid() );
160 spw = getspnam( pw->pw_name ); 160 spw = getspnam( pw->pw_name );
161 161
162 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); 162 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
163 if ( cpwd == "x" && spw ) 163 if ( cpwd == "x" && spw )
164 cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); 164 cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
165 165
166 // Note: some systems use more than crypt for passwords. 166 // Note: some systems use more than crypt for passwords.
167 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); 167 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
168 if ( cpwd == cpassword ) 168 if ( cpwd == cpassword )
169 return TRUE; 169 return TRUE;
170#endif 170#endif
171 171
172 static int lastdenial=0; 172 static int lastdenial=0;
173 static int denials=0; 173 static int denials=0;
174 int now = time(0); 174 int now = time(0);
175 175
176 Config cfg("Security"); 176 Config cfg("Security");
177 cfg.setGroup("SyncMode"); 177 cfg.setGroup("SyncMode");
178 int mode = cfg.readNumEntry("Mode", 0x02 ); 178 int mode = cfg.readNumEntry("Mode", 0x02 );
179 179
180 //No pass word needed if the user really needs it 180 //No pass word needed if the user really needs it
181 if (mode & 0x04) { 181 if (mode & 0x04) {
182 QMessageBox unauth( 182 QMessageBox unauth(
183 tr("Sync Connection"), 183 tr("Sync Connection"),
184 tr("<qt><p>An unauthorized system is requesting access to this device." 184 tr("<qt><p>An unauthorized system is requesting access to this device."
185 "<p>You chose IntelliSync so you may I allow or deny this connection.</qt>" ), 185 "<p>You chose IntelliSync so you may I allow or deny this connection.</qt>" ),
186 QMessageBox::Warning, 186 QMessageBox::Warning,
187 QMessageBox::Ok, QMessageBox::Cancel|QMessageBox::Default, QMessageBox::NoButton, 187 QMessageBox::Ok, QMessageBox::Cancel|QMessageBox::Default, QMessageBox::NoButton,
188 0, QString::null, TRUE, WStyle_StaysOnTop); 188 0, QString::null, TRUE, WStyle_StaysOnTop);
189 unauth.setButtonText(QMessageBox::Ok, tr("Allow" ) ); 189 unauth.setButtonText(QMessageBox::Ok, tr("Allow" ) );
190 unauth.setButtonText(QMessageBox::Cancel, tr("Deny")); 190 unauth.setButtonText(QMessageBox::Cancel, tr("Deny"));
191 switch( unauth.exec() ) { 191 switch( unauth.exec() ) {
192 case QMessageBox::Ok: 192 case QMessageBox::Ok:
193 return TRUE; 193 return TRUE;
194 break; 194 break;
195 case QMessageBox::Cancel: 195 case QMessageBox::Cancel:
196 default: 196 default:
197 denials++; 197 denials++;
198 lastdenial=now; 198 lastdenial=now;
199 return FALSE; 199 return FALSE;
200 } 200 }
201 } 201 }
202 202
203 // Detect old Qtopia Desktop (no password) and fail 203 // Detect old Qtopia Desktop (no password) and fail
204 if ( password.isEmpty() ) { 204 if ( password.isEmpty() ) {
205 if ( denials < 3 || now > lastdenial+600 ) { 205 if ( denials < 3 || now > lastdenial+600 ) {
206 QMessageBox unauth( 206 QMessageBox unauth(
207 tr("Sync Connection"), 207 tr("Sync Connection"),
208 tr("<p>An unauthorized system is requesting access to this device." 208 tr("<p>An unauthorized system is requesting access to this device."
209 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " 209 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, "
210 "please upgrade or change the security setting to use IntelliSync." ), 210 "please upgrade or change the security setting to use IntelliSync." ),
211 QMessageBox::Warning, 211 QMessageBox::Warning,
212 QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton, 212 QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton,
213 0, QString::null, TRUE, WStyle_StaysOnTop); 213 0, QString::null, TRUE, WStyle_StaysOnTop);
214 unauth.setButtonText(QMessageBox::Cancel, tr("Deny")); 214 unauth.setButtonText(QMessageBox::Cancel, tr("Deny"));
215 unauth.exec(); 215 unauth.exec();
216 216
217 denials++; 217 denials++;
218 lastdenial=now; 218 lastdenial=now;
219 } 219 }
220 return FALSE; 220 return FALSE;
221 221
222 } 222 }
223 223
224 // Second, check sync password... 224 // Second, check sync password...
225 225
226 static int lock=0; 226 static int lock=0;
227 if ( lock ) return FALSE; 227 if ( lock ) return FALSE;
228 228
229 ++lock; 229 ++lock;
230 230
231 /* 231 /*
232 * we need to support old Sync software and QtopiaDesktop 232 * we need to support old Sync software and QtopiaDesktop
233 */ 233 */
234 if ( password.left(6) == "Qtopia" || password.left(6) == "rootme" ) { 234 if ( password.left(6) == "Qtopia" || password.left(6) == "rootme" ) {
235 Config cfg( "Security" );
236 cfg.setGroup("Sync"); 235 cfg.setGroup("Sync");
237 QStringList pwds = cfg.readListEntry("Passwords",' '); 236 QStringList pwds = cfg.readListEntry("Passwords",' ');
238 for (QStringList::ConstIterator it=pwds.begin(); it!=pwds.end(); ++it) { 237 for (QStringList::ConstIterator it=pwds.begin(); it!=pwds.end(); ++it) {
239#ifndef Q_OS_WIN32 238#ifndef Q_OS_WIN32
240 QString cpassword = QString::fromLocal8Bit( 239 QString cpassword = QString::fromLocal8Bit(
241 crypt( password.mid(8).local8Bit(), (*it).left(2).latin1() ) ); 240 crypt( password.mid(8).local8Bit(), (*it).left(2).latin1() ) );
242#else 241#else
243 // ### revise 242 // ### revise
244 QString cpassword(""); 243 QString cpassword("");
245#endif 244#endif
246 if ( *it == cpassword ) { 245 if ( *it == cpassword ) {
247 lock--; 246 lock--;
248 return TRUE; 247 return TRUE;
249 } 248 }
250 } 249 }
251 250
252 // Unrecognized system. Be careful... 251 // Unrecognized system. Be careful...
253 QMessageBox unrecbox( 252 QMessageBox unrecbox(
254 tr("Sync Connection"), 253 tr("Sync Connection"),
255 tr( "<p>An unrecognized system is requesting access to this device." 254 tr( "<p>An unrecognized system is requesting access to this device."
256 "<p>If you have just initiated a Sync for the first time, this is normal."), 255 "<p>If you have just initiated a Sync for the first time, this is normal."),
257 QMessageBox::Warning, 256 QMessageBox::Warning,
258 QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::NoButton, 257 QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::NoButton,
259 0, QString::null, TRUE, WStyle_StaysOnTop); 258 0, QString::null, TRUE, WStyle_StaysOnTop);
260 unrecbox.setButtonText(QMessageBox::Cancel, tr("Deny")); 259 unrecbox.setButtonText(QMessageBox::Cancel, tr("Deny"));
261 unrecbox.setButtonText(QMessageBox::Yes, tr("Allow")); 260 unrecbox.setButtonText(QMessageBox::Yes, tr("Allow"));
262 261
263 if ( (denials > 2 && now < lastdenial+600) 262 if ( (denials > 2 && now < lastdenial+600)
264 || unrecbox.exec() != QMessageBox::Yes) 263 || unrecbox.exec() != QMessageBox::Yes)
265 { 264 {
266 denials++; 265 denials++;
267 lastdenial=now; 266 lastdenial=now;
268 lock--; 267 lock--;
269 return FALSE; 268 return FALSE;
270 } else { 269 } else {
271 const char salty[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."; 270 const char salty[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.";
272 char salt[2]; 271 char salt[2];
273 salt[0]= salty[rand() % (sizeof(salty)-1)]; 272 salt[0]= salty[rand() % (sizeof(salty)-1)];
274 salt[1]= salty[rand() % (sizeof(salty)-1)]; 273 salt[1]= salty[rand() % (sizeof(salty)-1)];
275#ifndef Q_OS_WIN32 274#ifndef Q_OS_WIN32
276 QString cpassword = QString::fromLocal8Bit( 275 QString cpassword = QString::fromLocal8Bit(
277 crypt( password.mid(8).local8Bit(), salt ) ); 276 crypt( password.mid(8).local8Bit(), salt ) );
278#else 277#else
279 //### revise 278 //### revise
280 QString cpassword(""); 279 QString cpassword("");
281#endif 280#endif
282 denials=0; 281 denials=0;
283 pwds.prepend(cpassword); 282 pwds.prepend(cpassword);
284 cfg.writeEntry("Passwords",pwds,' '); 283 cfg.writeEntry("Passwords",pwds,' ');
285 lock--; 284 lock--;
286 return TRUE; 285 return TRUE;
287 } 286 }
288 } 287 }
289 lock--; 288 lock--;
290 289
291 return FALSE; 290 return FALSE;
292} 291}
293 292
294 293
295ServerPI::ServerPI( int socket, QObject *parent, const char* name ) 294ServerPI::ServerPI( int socket, QObject *parent, const char* name )
296 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ), 295 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ),
297 storFileSize(-1) 296 storFileSize(-1)
298{ 297{
299 state = Connected; 298 state = Connected;
300 299
301 setSocket( socket ); 300 setSocket( socket );
302 301
303 peerport = peerPort(); 302 peerport = peerPort();
304 peeraddress = peerAddress(); 303 peeraddress = peerAddress();
305 304
306#ifndef INSECURE 305#ifndef INSECURE
307 if ( !SyncAuthentication::isAuthorized(peeraddress) ) { 306 if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
308 state = Forbidden; 307 state = Forbidden;
309 startTimer( 0 ); 308 startTimer( 0 );
310 } else 309 } else
311#endif 310#endif
312 { 311 {
313 connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); 312 connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
314 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); 313 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
315 314
316 passiv = FALSE; 315 passiv = FALSE;
317 for( int i = 0; i < 4; i++ ) 316 for( int i = 0; i < 4; i++ )
318 wait[i] = FALSE; 317 wait[i] = FALSE;
319 318
320 send( "220 Qtopia " QPE_VERSION " FTP Server" ); // No tr 319 send( "220 Qtopia " QPE_VERSION " FTP Server" ); // No tr
321 state = Wait_USER; 320 state = Wait_USER;
322 321
323 dtp = new ServerDTP( this ); 322 dtp = new ServerDTP( this );
324 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); 323 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
325 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); 324 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
326 connect( dtp, SIGNAL( error(int) ), SLOT( dtpError(int) ) ); 325 connect( dtp, SIGNAL( error(int) ), SLOT( dtpError(int) ) );
327 326
328 327
329 directory = QDir::currentDirPath(); 328 directory = QDir::currentDirPath();
330 329
331 static int p = 1024; 330 static int p = 1024;
332 331
333 while ( !serversocket || !serversocket->ok() ) { 332 while ( !serversocket || !serversocket->ok() ) {
334 delete serversocket; 333 delete serversocket;
335 serversocket = new ServerSocket( ++p, this ); 334 serversocket = new ServerSocket( ++p, this );
336 } 335 }
337 connect( serversocket, SIGNAL( newIncomming(int) ), 336 connect( serversocket, SIGNAL( newIncomming(int) ),
338 SLOT( newConnection(int) ) ); 337 SLOT( newConnection(int) ) );
339 } 338 }
340} 339}
341 340
342ServerPI::~ServerPI() 341ServerPI::~ServerPI()
343{ 342{
344 close(); 343 close();
345 344
346 if ( dtp ) 345 if ( dtp )
347 dtp->close(); 346 dtp->close();
348 delete dtp; 347 delete dtp;
349 delete serversocket; 348 delete serversocket;
350} 349}
351 350
352bool ServerPI::verifyAuthorised() 351bool ServerPI::verifyAuthorised()
353{ 352{
354 if ( !SyncAuthentication::isAuthorized(peerAddress()) ) { 353 if ( !SyncAuthentication::isAuthorized(peerAddress()) ) {
355 state = Forbidden; 354 state = Forbidden;
356 return FALSE; 355 return FALSE;
357 } 356 }
358 return TRUE; 357 return TRUE;
359} 358}
360 359
361void ServerPI::connectionClosed() 360void ServerPI::connectionClosed()
362{ 361{
363 // odebug << "Debug: Connection closed" << oendl; 362 // odebug << "Debug: Connection closed" << oendl;
364 emit connectionClosed(this); 363 emit connectionClosed(this);
365} 364}
366 365
367void ServerPI::send( const QString& msg ) 366void ServerPI::send( const QString& msg )
368{ 367{
369 QTextStream os( this ); 368 QTextStream os( this );
370 os << msg << endl; 369 os << msg << endl;
371 //odebug << "Reply: " << msg << "" << oendl; 370 //odebug << "Reply: " << msg << "" << oendl;
372} 371}
373 372
374void ServerPI::read() 373void ServerPI::read()
375{ 374{
376 while ( canReadLine() ) 375 while ( canReadLine() )
377 process( readLine().stripWhiteSpace() ); 376 process( readLine().stripWhiteSpace() );
378} 377}
379 378
380bool ServerPI::checkReadFile( const QString& file ) 379bool ServerPI::checkReadFile( const QString& file )
381{ 380{
382 QString filename; 381 QString filename;
383 382
384 if ( file[0] != "/" ) 383 if ( file.length() == 1 && file[0] == "/" )
384 filename = file;
385 else if ( file[0] != "/" )
385 filename = directory.path() + "/" + file; 386 filename = directory.path() + "/" + file;
386 else 387 else
387 filename = file; 388 filename = file;
388 389
389 QFileInfo fi( filename ); 390 QFileInfo fi( filename );
390 return ( fi.exists() && fi.isReadable() ); 391 return ( fi.exists() && fi.isReadable() );
391} 392}
392 393
393bool ServerPI::checkWriteFile( const QString& file ) 394bool ServerPI::checkWriteFile( const QString& file )
394{ 395{
395 QString filename; 396 QString filename;
396 397
397 if ( file[0] != "/" ) 398 if ( file[0] != "/" )
398 filename = directory.path() + "/" + file; 399 filename = directory.path() + "/" + file;
399 else 400 else
400 filename = file; 401 filename = file;
401 402
402 QFileInfo fi( filename ); 403 QFileInfo fi( filename );
403 404
404 if ( fi.exists() ) 405 if ( fi.exists() )
405 if ( !QFile( filename ).remove() ) 406 if ( !QFile( filename ).remove() )
406 return FALSE; 407 return FALSE;
407 return TRUE; 408 return TRUE;
408} 409}
409 410
410void ServerPI::process( const QString& message ) 411void ServerPI::process( const QString& message )
411{ 412{
412 //odebug << "Command: " << message << "" << oendl; 413 //odebug << "Command: " << message << "" << oendl;
413 414
414 // split message using "," as separator 415 // split message using "," as separator
415 QStringList msg = QStringList::split( " ", message ); 416 QStringList msg = QStringList::split( " ", message );
416 if ( msg.isEmpty() ) return; 417 if ( msg.isEmpty() ) return;
417 418
418 // command token 419 // command token
419 QString cmd = msg[0].upper(); 420 QString cmd = msg[0].upper();
420 421
421 // argument token 422 // argument token
422 QString arg; 423 QString arg;
423 if ( msg.count() >= 2 ) 424 if ( msg.count() >= 2 )
424 arg = msg[1]; 425 arg = msg[1];
425 426
426 // full argument string 427 // full argument string
427 QString args; 428 QString args;
428 if ( msg.count() >= 2 ) { 429 if ( msg.count() >= 2 ) {
429 QStringList copy( msg ); 430 QStringList copy( msg );
430 // FIXME: for Qt3 431 // FIXME: for Qt3
431 // copy.pop_front() 432 // copy.pop_front()
432 copy.remove( copy.begin() ); 433 copy.remove( copy.begin() );
433 args = copy.join( " " ); 434 args = copy.join( " " );
434 } 435 }
435 436
436 //odebug << "args: " << args << "" << oendl; 437 //odebug << "args: " << args << "" << oendl;
437 438
438 // we always respond to QUIT, regardless of state 439 // we always respond to QUIT, regardless of state
439 if ( cmd == "QUIT" ) { 440 if ( cmd == "QUIT" ) {
440 send( "211 Good bye!" ); // No tr 441 send( "211 Good bye!" ); // No tr
441 close(); 442 close();
442 return; 443 return;
443 } 444 }
444 445
445 // connected to client 446 // connected to client
446 if ( Connected == state ) 447 if ( Connected == state )
447 return; 448 return;
448 449
449 // waiting for user name 450 // waiting for user name
450 if ( Wait_USER == state ) { 451 if ( Wait_USER == state ) {
451 452
452 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { 453 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
453 send( "530 Please login with USER and PASS" ); // No tr 454 send( "530 Please login with USER and PASS" ); // No tr
454 return; 455 return;
455 } 456 }
456 send( "331 User name ok, need password" ); // No tr 457 send( "331 User name ok, need password" ); // No tr
457 state = Wait_PASS; 458 state = Wait_PASS;
458 return; 459 return;
459 } 460 }
460 461
461 // waiting for password 462 // waiting for password
462 if ( Wait_PASS == state ) { 463 if ( Wait_PASS == state ) {
463 464
464 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { 465 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
465 send( "530 Please login with USER and PASS" ); // No tr 466 send( "530 Please login with USER and PASS" ); // No tr
466 return; 467 return;
467 } 468 }
468 send( "230 User logged in, proceed" ); // No tr 469 send( "230 User logged in, proceed" ); // No tr
469 state = Ready; 470 state = Ready;
470 return; 471 return;
471 } 472 }
472 473
473 // ACCESS CONTROL COMMANDS 474 // ACCESS CONTROL COMMANDS
474 475
475 // Only an ALLO sent immediately before STOR is valid. 476 // Only an ALLO sent immediately before STOR is valid.
476 if ( cmd != "STOR" ) 477 if ( cmd != "STOR" )
477 storFileSize = -1; 478 storFileSize = -1;
478 479
479 // account (ACCT) 480 // account (ACCT)
480 if ( cmd == "ACCT" ) { 481 if ( cmd == "ACCT" ) {
481 // even wu-ftp does not support it 482 // even wu-ftp does not support it
482 send( "502 Command not implemented" ); // No tr 483 send( "502 Command not implemented" ); // No tr
483 } 484 }
484 485
485 // change working directory (CWD) 486 // change working directory (CWD)
486 else if ( cmd == "CWD" ) { 487 else if ( cmd == "CWD" ) {
487 488
488 if ( !args.isEmpty() ) { 489 if ( !args.isEmpty() ) {
489 if ( directory.cd( args, TRUE ) ) 490 if ( directory.cd( args, TRUE ) )
490 send( "250 Requested file action okay, completed" ); // No tr 491 send( "250 Requested file action okay, completed" ); // No tr
491 else 492 else
492 send( "550 Requested action not taken" ); // No tr 493 send( "550 Requested action not taken" ); // No tr
493 } 494 }
494 else 495 else
495 send( "500 Syntax error, command unrecognized" ); // No tr 496 send( "500 Syntax error, command unrecognized" ); // No tr
496 } 497 }
497 498
498 // change to parent directory (CDUP) 499 // change to parent directory (CDUP)
499 else if ( cmd == "CDUP" ) { 500 else if ( cmd == "CDUP" ) {
500 if ( directory.cdUp() ) 501 if ( directory.cdUp() )
501 send( "250 Requested file action okay, completed" ); // No tr 502 send( "250 Requested file action okay, completed" ); // No tr
502 else 503 else
503 send( "550 Requested action not taken" ); // No tr 504 send( "550 Requested action not taken" ); // No tr
504 } 505 }
505 506
506 // structure mount (SMNT) 507 // structure mount (SMNT)
507 else if ( cmd == "SMNT" ) { 508 else if ( cmd == "SMNT" ) {
508 // even wu-ftp does not support it 509 // even wu-ftp does not support it
509 send( "502 Command not implemented" ); // No tr 510 send( "502 Command not implemented" ); // No tr
510 } 511 }
511 512
512 // reinitialize (REIN) 513 // reinitialize (REIN)
513 else if ( cmd == "REIN" ) { 514 else if ( cmd == "REIN" ) {
514 // even wu-ftp does not support it 515 // even wu-ftp does not support it
515 send( "502 Command not implemented" ); // No tr 516 send( "502 Command not implemented" ); // No tr
516 } 517 }
517 518
518 519
519 // TRANSFER PARAMETER COMMANDS 520 // TRANSFER PARAMETER COMMANDS
520 521
521 522
522 // data port (PORT) 523 // data port (PORT)
523 else if ( cmd == "PORT" ) { 524 else if ( cmd == "PORT" ) {
524 if ( parsePort( arg ) ) 525 if ( parsePort( arg ) )
525 send( "200 Command okay" ); // No tr 526 send( "200 Command okay" ); // No tr
526 else 527 else
527 send( "500 Syntax error, command unrecognized" ); // No tr 528 send( "500 Syntax error, command unrecognized" ); // No tr
528 } 529 }
529 530
530 // passive (PASV) 531 // passive (PASV)
531 else if ( cmd == "PASV" ) { 532 else if ( cmd == "PASV" ) {
532 passiv = TRUE; 533 passiv = TRUE;
533 send( "227 Entering Passive Mode (" // No tr 534 send( "227 Entering Passive Mode (" // No tr
534 + address().toString().replace( QRegExp( "\\." ), "," ) + "," 535 + address().toString().replace( QRegExp( "\\." ), "," ) + ","
535 + QString::number( ( serversocket->port() ) >> 8 ) + "," 536 + QString::number( ( serversocket->port() ) >> 8 ) + ","
536 + QString::number( ( serversocket->port() ) & 0xFF ) +")" ); 537 + QString::number( ( serversocket->port() ) & 0xFF ) +")" );
537 } 538 }
538 539
539 // representation type (TYPE) 540 // representation type (TYPE)
540 else if ( cmd == "TYPE" ) { 541 else if ( cmd == "TYPE" ) {
541 if ( arg.upper() == "A" || arg.upper() == "I" ) 542 if ( arg.upper() == "A" || arg.upper() == "I" )
542 send( "200 Command okay" ); // No tr 543 send( "200 Command okay" ); // No tr
543 else 544 else
544 send( "504 Command not implemented for that parameter" ); // No tr 545 send( "504 Command not implemented for that parameter" ); // No tr
545 } 546 }
546 547
547 // file structure (STRU) 548 // file structure (STRU)
548 else if ( cmd == "STRU" ) { 549 else if ( cmd == "STRU" ) {
549 if ( arg.upper() == "F" ) 550 if ( arg.upper() == "F" )
550 send( "200 Command okay" ); // No tr 551 send( "200 Command okay" ); // No tr
551 else 552 else
552 send( "504 Command not implemented for that parameter" ); // No tr 553 send( "504 Command not implemented for that parameter" ); // No tr
553 } 554 }
554 555
555 // transfer mode (MODE) 556 // transfer mode (MODE)
556 else if ( cmd == "MODE" ) { 557 else if ( cmd == "MODE" ) {
557 if ( arg.upper() == "S" ) 558 if ( arg.upper() == "S" )
558 send( "200 Command okay" ); // No tr 559 send( "200 Command okay" ); // No tr
559 else 560 else
560 send( "504 Command not implemented for that parameter" ); // No tr 561 send( "504 Command not implemented for that parameter" ); // No tr
561 } 562 }
562 563
563 564
564 // FTP SERVICE COMMANDS 565 // FTP SERVICE COMMANDS
565 566
566 567
567 // retrieve (RETR) 568 // retrieve (RETR)
568 else if ( cmd == "RETR" ) 569 else if ( cmd == "RETR" )
569 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) ) 570 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
570 || backupRestoreGzip( absFilePath( args ) ) ) { 571 || backupRestoreGzip( absFilePath( args ) ) ) {
571 send( "150 File status okay" ); // No tr 572 send( "150 File status okay" ); // No tr
572 sendFile( absFilePath( args ) ); 573 sendFile( absFilePath( args ) );
573 } 574 }
574 else { 575 else {
575 odebug << "550 Requested action not taken" << oendl; 576 odebug << "550 Requested action not taken" << oendl;
576 send( "550 Requested action not taken" ); // No tr 577 send( "550 Requested action not taken" ); // No tr
577 } 578 }
578 579
579 // store (STOR) 580 // store (STOR)
580 else if ( cmd == "STOR" ) 581 else if ( cmd == "STOR" )
581 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) { 582 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
582 send( "150 File status okay" ); // No tr 583 send( "150 File status okay" ); // No tr
583 retrieveFile( absFilePath( args ) ); 584 retrieveFile( absFilePath( args ) );
584 } 585 }
585 else 586 else
586 send( "550 Requested action not taken" ); // No tr 587 send( "550 Requested action not taken" ); // No tr
587 588
588 // store unique (STOU) 589 // store unique (STOU)
589 else if ( cmd == "STOU" ) { 590 else if ( cmd == "STOU" ) {
590 send( "502 Command not implemented" ); // No tr 591 send( "502 Command not implemented" ); // No tr
591 } 592 }
592 593
593 // append (APPE) 594 // append (APPE)
594 else if ( cmd == "APPE" ) { 595 else if ( cmd == "APPE" ) {
595 send( "502 Command not implemented" ); // No tr 596 send( "502 Command not implemented" ); // No tr
596 } 597 }
597 598
598 // allocate (ALLO) 599 // allocate (ALLO)
599 else if ( cmd == "ALLO" ) { 600 else if ( cmd == "ALLO" ) {
600 storFileSize = args.toInt(); 601 storFileSize = args.toInt();
601 send( "200 Command okay" ); // No tr 602 send( "200 Command okay" ); // No tr
602 } 603 }
603 604
604 // restart (REST) 605 // restart (REST)
605 else if ( cmd == "REST" ) { 606 else if ( cmd == "REST" ) {
606 send( "502 Command not implemented" ); // No tr 607 send( "502 Command not implemented" ); // No tr
607 } 608 }
608 609
609 // rename from (RNFR) 610 // rename from (RNFR)
610 else if ( cmd == "RNFR" ) { 611 else if ( cmd == "RNFR" ) {
611 renameFrom = QString::null; 612 renameFrom = QString::null;
612 if ( args.isEmpty() ) 613 if ( args.isEmpty() )
613 send( "500 Syntax error, command unrecognized" ); // No tr 614 send( "500 Syntax error, command unrecognized" ); // No tr
614 else { 615 else {
615 QFile file( absFilePath( args ) ); 616 QFile file( absFilePath( args ) );
616 if ( file.exists() ) { 617 if ( file.exists() ) {
617 send( "350 File exists, ready for destination name" ); // No tr 618 send( "350 File exists, ready for destination name" ); // No tr
618 renameFrom = absFilePath( args ); 619 renameFrom = absFilePath( args );
619 } 620 }
620 else 621 else
621 send( "550 Requested action not taken" ); // No tr 622 send( "550 Requested action not taken" ); // No tr
622 } 623 }
623 } 624 }
624 625
625 // rename to (RNTO) 626 // rename to (RNTO)
626 else if ( cmd == "RNTO" ) { 627 else if ( cmd == "RNTO" ) {
627 if ( lastCommand != "RNFR" ) 628 if ( lastCommand != "RNFR" )
628 send( "503 Bad sequence of commands" ); // No tr 629 send( "503 Bad sequence of commands" ); // No tr
629 else if ( args.isEmpty() ) 630 else if ( args.isEmpty() )
630 send( "500 Syntax error, command unrecognized" ); // No tr 631 send( "500 Syntax error, command unrecognized" ); // No tr
631 else { 632 else {
632 QDir dir( absFilePath( args ) ); 633 QDir dir( absFilePath( args ) );
633 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) ) 634 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
634 send( "250 Requested file action okay, completed." ); // No tr 635 send( "250 Requested file action okay, completed." ); // No tr
635 else 636 else
636 send( "550 Requested action not taken" ); // No tr 637 send( "550 Requested action not taken" ); // No tr
637 } 638 }
638 } 639 }
639 640
640 // abort (ABOR) 641 // abort (ABOR)
641 else if ( cmd.contains( "ABOR" ) ) { 642 else if ( cmd.contains( "ABOR" ) ) {
642 dtp->close(); 643 dtp->close();
643 if ( dtp->dtpMode() != ServerDTP::Idle ) 644 if ( dtp->dtpMode() != ServerDTP::Idle )
644 send( "426 Connection closed; transfer aborted" ); // No tr 645 send( "426 Connection closed; transfer aborted" ); // No tr
645 else 646 else
646 send( "226 Closing data connection" ); // No tr 647 send( "226 Closing data connection" ); // No tr
647 } 648 }
648 649
649 // delete (DELE) 650 // delete (DELE)
650 else if ( cmd == "DELE" ) { 651 else if ( cmd == "DELE" ) {
651 if ( args.isEmpty() ) 652 if ( args.isEmpty() )
652 send( "500 Syntax error, command unrecognized" ); // No tr 653 send( "500 Syntax error, command unrecognized" ); // No tr
653 else { 654 else {
654 QFile file( absFilePath( args ) ) ; 655 QFile file( absFilePath( args ) ) ;
655 if ( file.remove() ) { 656 if ( file.remove() ) {
656 send( "250 Requested file action okay, completed" ); // No tr 657 send( "250 Requested file action okay, completed" ); // No tr
657 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 658 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
658 e << file.name(); 659 e << file.name();
659 } else { 660 } else {
660 send( "550 Requested action not taken" ); // No tr 661 send( "550 Requested action not taken" ); // No tr
661 } 662 }
662 } 663 }
663 } 664 }
664 665
665 // remove directory (RMD) 666 // remove directory (RMD)
666 else if ( cmd == "RMD" ) { 667 else if ( cmd == "RMD" ) {
667 if ( args.isEmpty() ) 668 if ( args.isEmpty() )
668 send( "500 Syntax error, command unrecognized" ); // No tr 669 send( "500 Syntax error, command unrecognized" ); // No tr
669 else { 670 else {
670 QDir dir; 671 QDir dir;
671 if ( dir.rmdir( absFilePath( args ), TRUE ) ) 672 if ( dir.rmdir( absFilePath( args ), TRUE ) )
672 send( "250 Requested file action okay, completed" ); // No tr 673 send( "250 Requested file action okay, completed" ); // No tr
673 else 674 else
674 send( "550 Requested action not taken" ); // No tr 675 send( "550 Requested action not taken" ); // No tr
675 } 676 }
676 } 677 }
677 678
678 // make directory (MKD) 679 // make directory (MKD)
679 else if ( cmd == "MKD" ) { 680 else if ( cmd == "MKD" ) {
680 if ( args.isEmpty() ) { 681 if ( args.isEmpty() ) {
681 odebug << " Error: no arg" << oendl; 682 odebug << " Error: no arg" << oendl;
682 send( "500 Syntax error, command unrecognized" ); // No tr 683 send( "500 Syntax error, command unrecognized" ); // No tr
683 } 684 }
684 else { 685 else {
685 QDir dir; 686 QDir dir;
686 if ( dir.mkdir( absFilePath( args ), TRUE ) ) 687 if ( dir.mkdir( absFilePath( args ), TRUE ) )
687 send( "250 Requested file action okay, completed." ); // No tr 688 send( "250 Requested file action okay, completed." ); // No tr
688 else 689 else
689 send( "550 Requested action not taken" ); // No tr 690 send( "550 Requested action not taken" ); // No tr
690 } 691 }
691 } 692 }
692 693
693 // print working directory (PWD) 694 // print working directory (PWD)
694 else if ( cmd == "PWD" ) { 695 else if ( cmd == "PWD" ) {
695 send( "257 \"" + directory.path() +"\"" ); 696 send( "257 \"" + directory.path() +"\"" );
696 } 697 }
697 698
698 // list (LIST) 699 // list (LIST)
699 else if ( cmd == "LIST" ) { 700 else if ( cmd == "LIST" ) {
701 if ( args == "-la" )
702 args = QString::null;
703
700 if ( sendList( absFilePath( args ) ) ) 704 if ( sendList( absFilePath( args ) ) )
701 send( "150 File status okay" ); // No tr 705 send( "150 File status okay" ); // No tr
702 else 706 else
703 send( "500 Syntax error, command unrecognized" ); // No tr 707 send( "500 Syntax error, command unrecognized" ); // No tr
704 } 708 }
705 709
706 // size (SIZE) 710 // size (SIZE)
707 else if ( cmd == "SIZE" ) { 711 else if ( cmd == "SIZE" ) {
708 QString filePath = absFilePath( args ); 712 QString filePath = absFilePath( args );
709 QFileInfo fi( filePath ); 713 QFileInfo fi( filePath );
710 bool gzipfile = backupRestoreGzip( filePath ); 714 bool gzipfile = backupRestoreGzip( filePath );
711 if ( !fi.exists() && !gzipfile ) 715 if ( !fi.exists() && !gzipfile )
712 send( "500 Syntax error, command unrecognized" ); // No tr 716 send( "500 Syntax error, command unrecognized" ); // No tr
713 else { 717 else {
714 if ( !gzipfile ) 718 if ( !gzipfile )
715 send( "213 " + QString::number( fi.size() ) ); 719 send( "213 " + QString::number( fi.size() ) );
716 else { 720 else {
717 Process duproc( QString("du") ); 721 Process duproc( QString("du") );
718 duproc.addArgument("-s"); 722 duproc.addArgument("-s");
719 QString in, out; 723 QString in, out;
720 if ( !duproc.exec(in, out) ) { 724 if ( !duproc.exec(in, out) ) {
721 odebug << "du process failed; just sending back 1K" << oendl; 725 odebug << "du process failed; just sending back 1K" << oendl;
722 send( "213 1024"); 726 send( "213 1024");
723 } 727 }
724 else { 728 else {
725 QString size = out.left( out.find("\t") ); 729 QString size = out.left( out.find("\t") );
726 int guess = size.toInt()/5; 730 int guess = size.toInt()/5;
727 if ( filePath.contains("doc") ) // No tr 731 if ( filePath.contains("doc") ) // No tr
728 guess *= 1000; 732 guess *= 1000;
729 odebug << "sending back gzip guess of " << guess << "" << oendl; 733 odebug << "sending back gzip guess of " << guess << "" << oendl;
730 send( "213 " + QString::number(guess) ); 734 send( "213 " + QString::number(guess) );
731 } 735 }
732 } 736 }
733 } 737 }
734 } 738 }
735 // name list (NLST) 739 // name list (NLST)
736 else if ( cmd == "NLST" ) { 740 else if ( cmd == "NLST" ) {
737 send( "502 Command not implemented" ); // No tr 741 send( "502 Command not implemented" ); // No tr
738 } 742 }
739 743
740 // site parameters (SITE) 744 // site parameters (SITE)
741 else if ( cmd == "SITE" ) { 745 else if ( cmd == "SITE" ) {
742 send( "502 Command not implemented" ); // No tr 746 send( "502 Command not implemented" ); // No tr
743 } 747 }
744 748
745 // system (SYST) 749 // system (SYST)
746 else if ( cmd == "SYST" ) { 750 else if ( cmd == "SYST" ) {
747 send( "215 UNIX Type: L8" ); // No tr 751 send( "215 UNIX Type: L8" ); // No tr
748 } 752 }
749 753
750 // status (STAT) 754 // status (STAT)
751 else if ( cmd == "STAT" ) { 755 else if ( cmd == "STAT" ) {
752 send( "502 Command not implemented" ); // No tr 756 send( "502 Command not implemented" ); // No tr
753 } 757 }
754 758
755 // help (HELP ) 759 // help (HELP )
756 else if ( cmd == "HELP" ) { 760 else if ( cmd == "HELP" ) {
757 send( "502 Command not implemented" ); // No tr 761 send( "502 Command not implemented" ); // No tr
758 } 762 }
759 763
760 // noop (NOOP) 764 // noop (NOOP)
761 else if ( cmd == "NOOP" ) { 765 else if ( cmd == "NOOP" ) {
762 send( "200 Command okay" ); // No tr 766 send( "200 Command okay" ); // No tr
763 } 767 }
764 768
765 // not implemented 769 // not implemented
766 else 770 else
767 send( "502 Command not implemented" ); // No tr 771 send( "502 Command not implemented" ); // No tr
768 772
769 lastCommand = cmd; 773 lastCommand = cmd;
770} 774}
771 775
772bool ServerPI::backupRestoreGzip( const QString &file ) 776bool ServerPI::backupRestoreGzip( const QString &file )
773{ 777{
774 return (file.find( "backup" ) != -1 && // No tr 778 return (file.find( "backup" ) != -1 && // No tr
775 file.findRev( ".tgz" ) == (int)file.length()-4 ); 779 file.findRev( ".tgz" ) == (int)file.length()-4 );
776} 780}
777 781
778bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets ) 782bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets )
779{ 783{
780 if ( file.find( "backup" ) != -1 && // No tr 784 if ( file.find( "backup" ) != -1 && // No tr
781 file.findRev( ".tgz" ) == (int)file.length()-4 ) { 785 file.findRev( ".tgz" ) == (int)file.length()-4 ) {
782 QFileInfo info( file ); 786 QFileInfo info( file );
783 targets = info.dirPath( TRUE ); 787 targets = info.dirPath( TRUE );
784 odebug << "ServerPI::backupRestoreGzip for " << file.latin1() << " = " << targets.join(" ").latin1() << oendl; 788 odebug << "ServerPI::backupRestoreGzip for " << file.latin1() << " = " << targets.join(" ").latin1() << oendl;
785 return true; 789 return true;
786 } 790 }
787 return false; 791 return false;
788} 792}
789 793
790void ServerPI::sendFile( const QString& file ) 794void ServerPI::sendFile( const QString& file )
791{ 795{
792 if ( passiv ) { 796 if ( passiv ) {
793 wait[SendFile] = TRUE; 797 wait[SendFile] = TRUE;
794 waitfile = file; 798 waitfile = file;
795 if ( waitsocket ) 799 if ( waitsocket )
796 newConnection( waitsocket ); 800 newConnection( waitsocket );
797 } 801 }
798 else { 802 else {
799 QStringList targets; 803 QStringList targets;
800 if ( backupRestoreGzip( file, targets ) ) 804 if ( backupRestoreGzip( file, targets ) )
801 dtp->sendGzipFile( file, targets, peeraddress, peerport ); 805 dtp->sendGzipFile( file, targets, peeraddress, peerport );
802 else dtp->sendFile( file, peeraddress, peerport ); 806 else dtp->sendFile( file, peeraddress, peerport );
803 } 807 }
804} 808}
805 809
806void ServerPI::retrieveFile( const QString& file ) 810void ServerPI::retrieveFile( const QString& file )
807{ 811{
808 if ( passiv ) { 812 if ( passiv ) {
809 wait[RetrieveFile] = TRUE; 813 wait[RetrieveFile] = TRUE;
810 waitfile = file; 814 waitfile = file;
811 if ( waitsocket ) 815 if ( waitsocket )
812 newConnection( waitsocket ); 816 newConnection( waitsocket );
813 } 817 }
814 else { 818 else {
815 QStringList targets; 819 QStringList targets;
816 if ( backupRestoreGzip( file, targets ) ) 820 if ( backupRestoreGzip( file, targets ) )
817 dtp->retrieveGzipFile( file, peeraddress, peerport ); 821 dtp->retrieveGzipFile( file, peeraddress, peerport );
818 else 822 else
819 dtp->retrieveFile( file, peeraddress, peerport, storFileSize ); 823 dtp->retrieveFile( file, peeraddress, peerport, storFileSize );
820 } 824 }
821} 825}
822 826
823bool ServerPI::parsePort( const QString& pp ) 827bool ServerPI::parsePort( const QString& pp )
824{ 828{
825 QStringList p = QStringList::split( ",", pp ); 829 QStringList p = QStringList::split( ",", pp );
826 if ( p.count() != 6 ) return FALSE; 830 if ( p.count() != 6 ) return FALSE;
827 831
828 // h1,h2,h3,h4,p1,p2 832 // h1,h2,h3,h4,p1,p2
829 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) + 833 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) +
830 ( p[2].toInt() << 8 ) + p[3].toInt() ); 834 ( p[2].toInt() << 8 ) + p[3].toInt() );
831 peerport = ( p[4].toInt() << 8 ) + p[5].toInt(); 835 peerport = ( p[4].toInt() << 8 ) + p[5].toInt();
832 return TRUE; 836 return TRUE;
833} 837}
834 838
835void ServerPI::dtpCompleted() 839void ServerPI::dtpCompleted()
836{ 840{
837 send( "226 Closing data connection, file transfer successful" ); // No tr 841 send( "226 Closing data connection, file transfer successful" ); // No tr
838 if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) { 842 if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) {
839 QString fn = dtp->fileName(); 843 QString fn = dtp->fileName();
840 if ( fn.right(8)==".desktop" && fn.find("/Documents/")>=0 ) { 844 if ( fn.right(8)==".desktop" && fn.find("/Documents/")>=0 ) {
841 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 845 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
842 e << fn; 846 e << fn;
843 } 847 }
844 } 848 }
845 waitsocket = 0; 849 waitsocket = 0;
846 dtp->close(); 850 dtp->close();
847 storFileSize = -1; 851 storFileSize = -1;
848} 852}
849 853
850void ServerPI::dtpFailed() 854void ServerPI::dtpFailed()
851{ 855{
852 dtp->close(); 856 dtp->close();
853 waitsocket = 0; 857 waitsocket = 0;
854 send( "451 Requested action aborted: local error in processing" ); // No tr 858 send( "451 Requested action aborted: local error in processing" ); // No tr
855 storFileSize = -1; 859 storFileSize = -1;
856} 860}
857 861
858void ServerPI::dtpError( int ) 862void ServerPI::dtpError( int )
859{ 863{
860 dtp->close(); 864 dtp->close();
861 waitsocket = 0; 865 waitsocket = 0;
862 send( "451 Requested action aborted: local error in processing" ); // No tr 866 send( "451 Requested action aborted: local error in processing" ); // No tr
863 storFileSize = -1; 867 storFileSize = -1;
864} 868}
865 869
866bool ServerPI::sendList( const QString& arg ) 870bool ServerPI::sendList( const QString& arg )
867{ 871{
868 QByteArray listing; 872 QByteArray listing;
869 QBuffer buffer( listing ); 873 QBuffer buffer( listing );
870 874
871 if ( !buffer.open( IO_WriteOnly ) ) 875 if ( !buffer.open( IO_WriteOnly ) )
872 return FALSE; 876 return FALSE;
873 877
874 QTextStream ts( &buffer ); 878 QTextStream ts( &buffer );
875 QString fn = arg; 879 QString fn = arg;
876 880
877 if ( fn.isEmpty() ) 881 if ( fn.isEmpty() )
878 fn = directory.path(); 882 fn = directory.path();
879 883
880 QFileInfo fi( fn ); 884 QFileInfo fi( fn );
881 if ( !fi.exists() ) return FALSE; 885 if ( !fi.exists() ) return FALSE;
882 886
883 // return file listing 887 // return file listing
884 if ( fi.isFile() ) { 888 if ( fi.isFile() ) {
885 ts << fileListing( &fi ) << endl; 889 ts << fileListing( &fi ) << endl;
886 } 890 }
887 891
888 // return directory listing 892 // return directory listing
889 else if ( fi.isDir() ) { 893 else if ( fi.isDir() ) {
890 QDir dir( fn ); 894 QDir dir( fn );
891 const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden ); 895 const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden );
892 896
893 QFileInfoListIterator it( *list ); 897 QFileInfoListIterator it( *list );
894 QFileInfo *info; 898 QFileInfo *info;
895 899
896 unsigned long total = 0; 900 unsigned long total = 0;
897 while ( ( info = it.current() ) ) { 901 while ( ( info = it.current() ) ) {
898 if ( info->fileName() != "." && info->fileName() != ".." ) 902 if ( info->fileName() != "." && info->fileName() != ".." )
899 total += info->size(); 903 total += info->size();
900 ++it; 904 ++it;
901 } 905 }
902 906
903 ts << "total " << QString::number( total / 1024 ) << endl; // No tr 907 ts << "total " << QString::number( total / 1024 ) << endl; // No tr
904 908
905 it.toFirst(); 909 it.toFirst();
906 while ( ( info = it.current() ) ) { 910 while ( ( info = it.current() ) ) {
907 if ( info->fileName() == "." || info->fileName() == ".." ) { 911 if ( info->fileName() == "." || info->fileName() == ".." ) {
908 ++it; 912 ++it;
909 continue; 913 continue;
910 } 914 }
911 ts << fileListing( info ) << endl; 915 ts << fileListing( info ) << endl;
912 ++it; 916 ++it;
913 } 917 }
914 } 918 }
915 919
916 if ( passiv ) { 920 if ( passiv ) {
917 waitarray = buffer.buffer(); 921 waitarray = buffer.buffer();
918 wait[SendByteArray] = TRUE; 922 wait[SendByteArray] = TRUE;
919 if ( waitsocket ) 923 if ( waitsocket )
920 newConnection( waitsocket ); 924 newConnection( waitsocket );
921 } 925 }
922 else 926 else
923 dtp->sendByteArray( buffer.buffer(), peeraddress, peerport ); 927 dtp->sendByteArray( buffer.buffer(), peeraddress, peerport );
924 return TRUE; 928 return TRUE;
925} 929}
926 930
927QString ServerPI::fileListing( QFileInfo *info ) 931QString ServerPI::fileListing( QFileInfo *info )
928{ 932{
929 if ( !info ) return QString::null; 933 if ( !info ) return QString::null;
930 QString s; 934 QString s;
931 935
932 // type char 936 // type char
933 if ( info->isDir() ) 937 if ( info->isDir() )
934 s += "d"; 938 s += "d";
935 else if ( info->isSymLink() ) 939 else if ( info->isSymLink() )
936 s += "l"; 940 s += "l";
937 else 941 else
938 s += "-"; 942 s += "-";
939 943
940 // permisson string 944 // permisson string
941 s += permissionString( info ) + " "; 945 s += permissionString( info ) + " ";
942 946
943 // number of hardlinks 947 // number of hardlinks
944 int subdirs = 1; 948 int subdirs = 1;
945 949
946 if ( info->isDir() ) 950 if ( info->isDir() )
947 subdirs = 2; 951 subdirs = 2;
948 // FIXME : this is to slow 952 // FIXME : this is to slow
949 //if ( info->isDir() ) 953 //if ( info->isDir() )
950 //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count(); 954 //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count();
951 955
952 s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " "; 956 s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " ";
953 957
954 // owner 958 // owner
955 QString o = info->owner(); 959 QString o = info->owner();