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
@@ -156,385 +156,387 @@ int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
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)