/* -------------------------------------------------------------
dict . cpp ( part of The KDE Dictionary Client )
Copyright ( C ) 2000 - 2001 Christian Gebauer < gebauer @ kde . org >
( C ) by Matthias H <EFBFBD> lzer 1998
This file is distributed under the Artistic License .
See LICENSE for details .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
JobData used for data transfer between Client and Interface
DictAsyncClient all network related stuff happens here in asynchrous thread
DictInterface interface for DictAsyncClient , job management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# include <config.h>
# include "application.h"
# include "options.h"
# include "dict.h"
# include <tqregexp.h>
# include <tqtextcodec.h>
# include <klocale.h>
# include <kdebug.h>
# include <kmessagebox.h>
# include <kmdcodec.h>
# include <kextsock.h>
# include <ksocks.h>
# include <errno.h>
# include <unistd.h>
# include <fcntl.h>
# include <signal.h>
# include <stdlib.h>
//********* JobData ******************************************
JobData : : JobData ( QueryType Ntype , bool NnewServer , TQString const & Nserver , int Nport ,
int NidleHold , int Ntimeout , int NpipeSize , TQString const & Nencoding , bool NAuthEnabled ,
TQString const & Nuser , TQString const & Nsecret , unsigned int NheadLayout )
: type ( Ntype ) , error ( ErrNoErr ) , canceled ( false ) , numFetched ( 0 ) , newServer ( NnewServer ) , server ( Nserver ) , port ( Nport ) ,
timeout ( Ntimeout ) , pipeSize ( NpipeSize ) , idleHold ( NidleHold ) , encoding ( Nencoding ) , authEnabled ( NAuthEnabled ) ,
user ( Nuser ) , secret ( Nsecret ) , headLayout ( NheadLayout )
{ }
//********* DictAsyncClient *************************************
DictAsyncClient : : DictAsyncClient ( int NfdPipeIn , int NfdPipeOut )
: job ( 0L ) , inputSize ( 10000 ) , fdPipeIn ( NfdPipeIn ) ,
fdPipeOut ( NfdPipeOut ) , tcpSocket ( - 1 ) , idleHold ( 0 )
{
input = new char [ inputSize ] ;
}
DictAsyncClient : : ~ DictAsyncClient ( )
{
if ( - 1 ! = tcpSocket )
doQuit ( ) ;
delete [ ] input ;
}
void * DictAsyncClient : : startThread ( void * pseudoThis )
{
DictAsyncClient * newthis = ( DictAsyncClient * ) ( pseudoThis ) ;
if ( 0 ! = pthread_setcanceltype ( PTHREAD_CANCEL_ENABLE , NULL ) )
qWarning ( " pthread_setcanceltype failed! " ) ;
if ( 0 ! = pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) )
qWarning ( " pthread_setcanceltype failed! " ) ;
signal ( SIGPIPE , SIG_IGN ) ; // ignore sigpipe
newthis - > waitForWork ( ) ;
return NULL ;
}
void DictAsyncClient : : insertJob ( JobData * newJob )
{
if ( ! job ) // don't overwrite existing job pointer
job = newJob ;
}
void DictAsyncClient : : removeJob ( )
{
job = 0L ;
}
void DictAsyncClient : : waitForWork ( )
{
fd_set fdsR , fdsE ;
timeval tv ;
int selectRet ;
char buf ;
while ( true ) {
if ( tcpSocket ! = - 1 ) { // we are connected, hold the connection for xx secs
FD_ZERO ( & fdsR ) ;
FD_SET ( fdPipeIn , & fdsR ) ;
FD_SET ( tcpSocket , & fdsR ) ;
FD_ZERO ( & fdsE ) ;
FD_SET ( tcpSocket , & fdsE ) ;
tv . tv_sec = idleHold ;
tv . tv_usec = 0 ;
selectRet = KSocks : : self ( ) - > select ( FD_SETSIZE , & fdsR , NULL , & fdsE , & tv ) ;
if ( selectRet = = 0 ) {
doQuit ( ) ; // nothing happend...
} else {
if ( ( ( selectRet > 0 ) & & ( ! FD_ISSET ( fdPipeIn , & fdsR ) ) ) | | ( selectRet = = - 1 ) )
closeSocket ( ) ;
}
}
do {
FD_ZERO ( & fdsR ) ;
FD_SET ( fdPipeIn , & fdsR ) ;
} while ( select ( FD_SETSIZE , & fdsR , NULL , NULL , NULL ) < 0 ) ; // don't get tricked by signals
clearPipe ( ) ;
if ( job ) {
if ( ( tcpSocket ! = - 1 ) & & ( job - > newServer ) )
doQuit ( ) ;
codec = TQTextCodec : : codecForName ( job - > encoding . latin1 ( ) ) ;
input [ 0 ] = 0 ; //terminate string
thisLine = input ;
nextLine = input ;
inputEnd = input ;
timeout = job - > timeout ;
idleHold = job - > idleHold ;
if ( tcpSocket = = - 1 )
openConnection ( ) ;
if ( tcpSocket ! = - 1 ) { // connection is ready
switch ( job - > type ) {
case JobData : : TDefine :
define ( ) ;
break ;
case JobData : : TGetDefinitions :
getDefinitions ( ) ;
break ;
case JobData : : TMatch :
match ( ) ;
break ;
case JobData : : TShowDatabases :
showDatabases ( ) ;
break ;
case JobData : : TShowDbInfo :
showDbInfo ( ) ;
break ;
case JobData : : TShowStrategies :
showStrategies ( ) ;
break ;
case JobData : : TShowInfo :
showInfo ( ) ;
break ;
case JobData : : TUpdate :
update ( ) ;
}
}
clearPipe ( ) ;
}
if ( write ( fdPipeOut , & buf , 1 ) = = - 1 ) // emit stopped signal
: : perror ( " waitForJobs() " ) ;
}
}
void DictAsyncClient : : define ( )
{
TQString command ;
job - > defines . clear ( ) ;
TQStringList : : iterator it ;
for ( it = job - > databases . begin ( ) ; it ! = job - > databases . end ( ) ; + + it ) {
command = " define " ;
command + = * it ;
command + = " \" " ;
command + = job - > query ;
command + = " \" \r \n " ;
job - > defines . append ( command ) ;
}
if ( ! getDefinitions ( ) )
return ;
if ( job - > numFetched = = 0 ) {
job - > strategy = " . " ;
if ( ! match ( ) )
return ;
job - > result = TQString ( ) ;
if ( job - > numFetched = = 0 ) {
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " No definitions found for \' %1'. " ) . tqarg ( job - > query ) ) ;
resultAppend ( " </p> \n </html></body> " ) ;
} else {
// html header...
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " No definitions found for \' %1 \' . Perhaps you mean: " ) . tqarg ( job - > query ) ) ;
resultAppend ( " </p> \n <table width= \" 100% \" cols=2> \n " ) ;
TQString lastDb ;
TQStringList : : iterator it ;
for ( it = job - > matches . begin ( ) ; it ! = job - > matches . end ( ) ; + + it ) {
int pos = ( * it ) . find ( ' ' ) ;
if ( pos ! = - 1 ) {
if ( lastDb ! = ( * it ) . left ( pos ) ) {
if ( lastDb . length ( ) > 0 )
resultAppend ( " </pre></td></tr> \n " ) ;
lastDb = ( * it ) . left ( pos ) ;
resultAppend ( " <tr valign=top><td width=25%><pre><b> " ) ;
resultAppend ( lastDb ) ;
resultAppend ( " :</b></pre></td><td width=75%><pre> " ) ;
}
if ( ( * it ) . length ( ) > ( unsigned int ) pos + 2 ) {
resultAppend ( " <a href= \" http://define/ " ) ;
resultAppend ( ( * it ) . mid ( pos + 2 , ( * it ) . length ( ) - pos - 3 ) ) ;
resultAppend ( " \" > " ) ;
resultAppend ( ( * it ) . mid ( pos + 2 , ( * it ) . length ( ) - pos - 3 ) ) ;
resultAppend ( " </a> " ) ;
}
}
}
resultAppend ( " \n </pre></td></tr></table> \n </body></html> " ) ;
job - > numFetched = 0 ;
}
}
}
TQString htmlString ( const TQString & raw )
{
unsigned int len = raw . length ( ) ;
TQString ret ;
for ( unsigned int i = 0 ; i < len ; i + + ) {
switch ( raw [ i ] ) {
case ' & ' : ret + = " & " ; break ;
case ' < ' : ret + = " < " ; break ;
case ' > ' : ret + = " > " ; break ;
default : ret + = raw [ i ] ;
}
}
return ret ;
}
TQString generateDefineLink ( const TQString & raw )
{
TQRegExp http ( " http://[^ \\ s<>() \ " | \\ [ \\ ] { } ] + " );
TQRegExp ftp ( " ftp://[^ \\ s<>() \ " | \\ [ \\ ] { } ] + " );
int matchPos = 0 , matchLen = 0 ;
bool httpMatch = false ;
TQString ret ;
matchPos = http . search ( raw ) ;
matchLen = http . matchedLength ( ) ;
if ( - 1 ! = matchPos ) {
httpMatch = true ;
} else {
matchPos = ftp . search ( raw ) ;
matchLen = ftp . matchedLength ( ) ;
httpMatch = false ;
}
if ( - 1 ! = matchPos ) {
ret = htmlString ( raw . left ( matchPos ) ) ;
ret + = " <a href= \" http:// " ;
if ( httpMatch ) {
ret + = " realhttp/ " ;
ret + = raw . mid ( matchPos + 7 , matchLen - 7 ) ;
} else {
ret + = " realftp/ " ;
ret + = raw . mid ( matchPos + 6 , matchLen - 6 ) ;
}
ret + = " \" > " ;
ret + = htmlString ( raw . mid ( matchPos , matchLen ) ) ;
ret + = " </a> " ;
ret + = htmlString ( raw . right ( raw . length ( ) - matchLen - matchPos ) ) ;
} else {
ret = " <a href= \" http://define/ " ;
ret + = raw ;
ret + = " \" > " ;
ret + = htmlString ( raw ) ;
ret + = " </a> " ;
}
return ret ;
}
bool DictAsyncClient : : getDefinitions ( )
{
TQCString lastDb , bracketBuff ;
TQStrList hashList ;
char * s ;
int defCount , response ;
// html header...
resultAppend ( " <body> \n " ) ;
while ( job - > defines . count ( ) > 0 ) {
defCount = 0 ;
cmdBuffer = " " ;
do {
TQStringList : : iterator it = job - > defines . begin ( ) ;
cmdBuffer + = codec - > fromUnicode ( * it ) ;
defCount + + ;
job - > defines . remove ( it ) ;
} while ( ( job - > defines . count ( ) > 0 ) & & ( ( int ) cmdBuffer . length ( ) < job - > pipeSize ) ) ;
if ( ! sendBuffer ( ) )
return false ;
for ( ; defCount > 0 ; defCount - - ) {
if ( ! getNextResponse ( response ) )
return false ;
switch ( response ) {
case 552 : // define: 552 No match
break ;
case 150 : { // define: 150 n definitions retrieved - definitions follow
bool defineDone = false ;
while ( ! defineDone ) {
if ( ! getNextResponse ( response ) )
return false ;
switch ( response ) {
case 151 : { // define: 151 word database name - text follows
char * db = strchr ( thisLine , ' \" ' ) ;
if ( db )
db = strchr ( db + 1 , ' \" ' ) ;
char * dbdes = 0 ;
if ( db ) {
db + = 2 ; // db points now on database name
dbdes = strchr ( db , ' ' ) ;
if ( dbdes ) {
dbdes [ 0 ] = 0 ; // terminate database name
dbdes + = 2 ; // dbdes points now on database description
}
} else {
job - > error = JobData : : ErrServerError ;
job - > result = TQString ( ) ;
resultAppend ( thisLine ) ;
doQuit ( ) ;
return false ;
}
int oldResPos = job - > result . length ( ) ;
if ( ( ( job - > headLayout < 2 ) & & ( lastDb ! = db ) ) | | ( job - > headLayout = = 2 ) ) {
lastDb = db ;
resultAppend ( " <p class= \" heading \" > \n " ) ;
if ( dbdes )
resultAppend ( codec - > toUnicode ( dbdes , strlen ( dbdes ) - 1 ) ) ;
resultAppend ( " [<a href= \" http://dbinfo/ " ) ;
resultAppend ( db ) ;
resultAppend ( " \" > " ) ;
resultAppend ( db ) ;
resultAppend ( " </a>]</p> \n " ) ;
} else
if ( job - > headLayout = = 1 )
resultAppend ( " <hr> \n " ) ;
resultAppend ( " <pre><p class= \" definition \" > \n " ) ;
KMD5 context ;
bool bodyDone = false ;
while ( ! bodyDone ) {
if ( ! getNextLine ( ) )
return false ;
char * line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
bodyDone = true ;
}
if ( ! bodyDone ) {
context . update ( TQCString ( line ) ) ;
if ( ! bracketBuff . isEmpty ( ) ) {
s = strchr ( line , ' } ' ) ;
if ( ! s )
resultAppend ( bracketBuff . data ( ) ) ;
else {
s [ 0 ] = 0 ;
bracketBuff . remove ( 0 , 1 ) ; // remove '{'
bracketBuff + = line ;
line = s + 1 ;
resultAppend ( generateDefineLink ( codec - > toUnicode ( bracketBuff ) ) ) ;
}
bracketBuff = " " ;
}
s = strchr ( line , ' { ' ) ;
while ( s ) {
resultAppend ( htmlString ( codec - > toUnicode ( line , s - line ) ) ) ;
line = s ;
s = strchr ( line , ' } ' ) ;
if ( s ) {
s [ 0 ] = 0 ;
line + + ;
resultAppend ( generateDefineLink ( codec - > toUnicode ( line ) ) ) ;
line = s + 1 ;
s = strchr ( line , ' { ' ) ;
} else {
bracketBuff = line ;
bracketBuff + = " \n " ;
line = 0 ;
s = 0 ;
}
}
if ( line ) {
resultAppend ( htmlString ( codec - > toUnicode ( line ) ) ) ;
resultAppend ( " \n " ) ;
}
}
}
resultAppend ( " </p></pre> \n " ) ;
if ( hashList . find ( context . hexDigest ( ) ) > = 0 ) // duplicate??
job - > result . truncate ( oldResPos ) ; // delete the whole definition
else {
hashList . append ( context . hexDigest ( ) ) ;
job - > numFetched + + ;
}
break ; }
case 250 : { // define: 250 ok (optional timing information here)
defineDone = true ;
break ; }
default : {
handleErrors ( ) ;
return false ; }
}
}
break ; }
default :
handleErrors ( ) ;
return false ;
}
}
}
resultAppend ( " </body></html> \n " ) ;
return true ;
}
bool DictAsyncClient : : match ( )
{
TQStringList : : iterator it = job - > databases . begin ( ) ;
int response ;
cmdBuffer = " " ;
while ( it ! = job - > databases . end ( ) ) {
int send = 0 ;
do {
cmdBuffer + = " match " ;
cmdBuffer + = codec - > fromUnicode ( * ( it ) ) ;
cmdBuffer + = " " ;
cmdBuffer + = codec - > fromUnicode ( job - > strategy ) ;
cmdBuffer + = " \" " ;
cmdBuffer + = codec - > fromUnicode ( job - > query ) ;
cmdBuffer + = " \" \r \n " ;
send + + ;
+ + it ;
} while ( ( it ! = job - > databases . end ( ) ) & & ( ( int ) cmdBuffer . length ( ) < job - > pipeSize ) ) ;
if ( ! sendBuffer ( ) )
return false ;
for ( ; send > 0 ; send - - ) {
if ( ! getNextResponse ( response ) )
return false ;
switch ( response ) {
case 552 : // match: 552 No match
break ;
case 152 : { // match: 152 n matches found - text follows
bool matchDone = false ;
while ( ! matchDone ) {
if ( ! getNextLine ( ) )
return false ;
char * line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double period into one
else
if ( line [ 1 ] = = 0 )
matchDone = true ;
}
if ( ! matchDone ) {
job - > numFetched + + ;
job - > matches . append ( codec - > toUnicode ( line ) ) ;
}
}
if ( ! nextResponseOk ( 250 ) ) // match: "250 ok ..."
return false ;
break ; }
default :
handleErrors ( ) ;
return false ;
}
}
}
return true ;
}
void DictAsyncClient : : showDatabases ( )
{
cmdBuffer = " show db \r \n " ;
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 110 ) ) // show db: "110 n databases present - text follows "
return ;
// html header...
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " Available Databases: " ) ) ;
resultAppend ( " \n </p> \n <table width= \" 100% \" cols=2> \n " ) ;
bool done ( false ) ;
char * line ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
resultAppend ( " <tr valign=top><td width=25%><pre><a href= \" http://dbinfo/ " ) ;
char * space = strchr ( line , ' ' ) ;
if ( space ) {
resultAppend ( codec - > toUnicode ( line , space - line ) ) ;
resultAppend ( " \" > " ) ;
resultAppend ( codec - > toUnicode ( line , space - line ) ) ;
resultAppend ( " </a></pre></td><td width=75%><pre> " ) ;
line = space + 1 ;
if ( line [ 0 ] = = ' " ' ) {
line + + ; // remove double quote
char * quote = strchr ( line , ' \" ' ) ;
if ( quote )
quote [ 0 ] = 0 ;
}
} else { // hmmm, malformated line...
resultAppend ( " \" ></a></pre></td><td width=75%> " ) ;
}
resultAppend ( line ) ;
resultAppend ( " </pre></td></tr> \n " ) ;
}
}
resultAppend ( " </table> \n </body></html> " ) ;
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
}
void DictAsyncClient : : showDbInfo ( )
{
cmdBuffer = " show info " ;
cmdBuffer + = codec - > fromUnicode ( job - > query ) ;
cmdBuffer + = " \r \n " ;
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 112 ) ) // show info db: "112 database information follows"
return ;
// html header...
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " Database Information [%1]: " ) . tqarg ( job - > query ) ) ;
resultAppend ( " </p> \n <pre><p class= \" definition \" > \n " ) ;
bool done ( false ) ;
char * line ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
resultAppend ( line ) ;
resultAppend ( " \n " ) ;
}
}
resultAppend ( " </p></pre> \n </body></html> " ) ;
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
}
void DictAsyncClient : : showStrategies ( )
{
cmdBuffer = " show strat \r \n " ;
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 111 ) ) // show strat: "111 n strategies present - text follows "
return ;
// html header...
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " Available Strategies: " ) ) ;
resultAppend ( " \n </p> \n <table width= \" 100% \" cols=2> \n " ) ;
bool done ( false ) ;
char * line ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
resultAppend ( " <tr valign=top><td width=25%><pre> " ) ;
char * space = strchr ( line , ' ' ) ;
if ( space ) {
resultAppend ( codec - > toUnicode ( line , space - line ) ) ;
resultAppend ( " </pre></td><td width=75%><pre> " ) ;
line = space + 1 ;
if ( line [ 0 ] = = ' " ' ) {
line + + ; // remove double quote
char * quote = strchr ( line , ' \" ' ) ;
if ( quote )
quote [ 0 ] = 0 ;
}
} else { // hmmm, malformated line...
resultAppend ( " </pre></td><td width=75%><pre> " ) ;
}
resultAppend ( line ) ;
resultAppend ( " </pre></td></tr> \n " ) ;
}
}
resultAppend ( " </table> \n </body></html> " ) ;
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
}
void DictAsyncClient : : showInfo ( )
{
cmdBuffer = " show server \r \n " ;
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 114 ) ) // show server: "114 server information follows"
return ;
// html header...
resultAppend ( " <body> \n <p class= \" heading \" > \n " ) ;
resultAppend ( i18n ( " Server Information: " ) ) ;
resultAppend ( " \n </p> \n <pre><p class= \" definition \" > \n " ) ;
bool done ( false ) ;
char * line ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
resultAppend ( line ) ;
resultAppend ( " \n " ) ;
}
}
resultAppend ( " </p></pre> \n </body></html> " ) ;
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
}
void DictAsyncClient : : update ( )
{
cmdBuffer = " show strat \r \n show db \r \n " ;
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 111 ) ) // show strat: "111 n strategies present - text follows "
return ;
bool done ( false ) ;
char * line ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
char * space = strchr ( line , ' ' ) ;
if ( space ) space [ 0 ] = 0 ; // terminate string, hack ;-)
job - > strategies . append ( codec - > toUnicode ( line ) ) ;
}
}
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
if ( ! nextResponseOk ( 110 ) ) // show db: "110 n databases present - text follows "
return ;
done = false ;
while ( ! done ) {
if ( ! getNextLine ( ) )
return ;
line = thisLine ;
if ( line [ 0 ] = = ' . ' ) {
if ( line [ 1 ] = = ' . ' )
line + + ; // collapse double periode into one
else
if ( line [ 1 ] = = 0 )
done = true ;
}
if ( ! done ) {
char * space = strchr ( line , ' ' ) ;
if ( space ) space [ 0 ] = 0 ; // terminate string, hack ;-)
job - > databases . append ( codec - > toUnicode ( line ) ) ;
}
}
if ( ! nextResponseOk ( 250 ) ) // end of transmission: "250 ok ..."
return ;
}
// connect, handshake and authorization
void DictAsyncClient : : openConnection ( )
{
if ( job - > server . isEmpty ( ) ) {
job - > error = JobData : : ErrBadHost ;
return ;
}
KExtendedSocket ks ;
ks . setAddress ( job - > server , job - > port ) ;
ks . setTimeout ( job - > timeout ) ;
if ( ks . connect ( ) < 0 ) {
if ( ks . status ( ) = = IO_LookupError )
job - > error = JobData : : ErrBadHost ;
else if ( ks . status ( ) = = IO_ConnectError ) {
job - > result = TQString ( ) ;
resultAppend ( KExtendedSocket : : strError ( ks . status ( ) , errno ) ) ;
job - > error = JobData : : ErrConnect ;
} else if ( ks . status ( ) = = IO_TimeOutError )
job - > error = JobData : : ErrTimeout ;
else {
job - > result = TQString ( ) ;
resultAppend ( KExtendedSocket : : strError ( ks . status ( ) , errno ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return ;
}
tcpSocket = ks . fd ( ) ;
ks . release ( ) ;
if ( ! nextResponseOk ( 220 ) ) // connect: "220 text capabilities msg-id"
return ;
cmdBuffer = " client \" Kdict " ;
cmdBuffer + = KDICT_VERSION ;
cmdBuffer + = " \" \r \n " ;
if ( job - > authEnabled )
if ( strstr ( thisLine , " auth " ) ) { // skip auth if not supported
char * msgId = strrchr ( thisLine , ' < ' ) ;
if ( ( ! msgId ) | | ( ! job - > user . length ( ) ) ) {
job - > error = JobData : : ErrAuthFailed ;
closeSocket ( ) ;
return ;
}
KMD5 context ;
context . update ( TQCString ( msgId ) ) ;
context . update ( job - > secret . local8Bit ( ) ) ;
cmdBuffer + = " auth " + job - > user . local8Bit ( ) + " " ;
cmdBuffer + = context . hexDigest ( ) ;
cmdBuffer + = " \r \n " ;
}
if ( ! sendBuffer ( ) )
return ;
if ( ! nextResponseOk ( 250 ) ) // client: "250 ok ..."
return ;
if ( job - > authEnabled )
if ( ! nextResponseOk ( 230 ) ) // auth: "230 Authentication successful"
return ;
}
void DictAsyncClient : : closeSocket ( )
{
if ( - 1 ! = tcpSocket ) {
: : close ( tcpSocket ) ;
tcpSocket = - 1 ;
}
}
// send "quit" without timeout, without checks, close connection
void DictAsyncClient : : doQuit ( )
{
fd_set fdsW ;
timeval tv ;
FD_ZERO ( & fdsW ) ;
FD_SET ( tcpSocket , & fdsW ) ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
int ret = KSocks : : self ( ) - > select ( FD_SETSIZE , NULL , & fdsW , NULL , & tv ) ;
if ( ret > 0 ) { // we can write...
cmdBuffer = " quit \r \n " ;
int todo = cmdBuffer . length ( ) ;
KSocks : : self ( ) - > write ( tcpSocket , & cmdBuffer . data ( ) [ 0 ] , todo ) ;
}
closeSocket ( ) ;
}
// used by getNextLine()
bool DictAsyncClient : : waitForRead ( )
{
fd_set fdsR , fdsE ;
timeval tv ;
int ret ;
do {
FD_ZERO ( & fdsR ) ;
FD_SET ( fdPipeIn , & fdsR ) ;
FD_SET ( tcpSocket , & fdsR ) ;
FD_ZERO ( & fdsE ) ;
FD_SET ( tcpSocket , & fdsE ) ;
FD_SET ( fdPipeIn , & fdsE ) ;
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
ret = KSocks : : self ( ) - > select ( FD_SETSIZE , & fdsR , NULL , & fdsE , & tv ) ;
} while ( ( ret < 0 ) & & ( errno = = EINTR ) ) ; // don't get tricked by signals
if ( ret = = - 1 ) { // select failed
if ( job ) {
job - > result = TQString ( ) ;
resultAppend ( strerror ( errno ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
if ( ret = = 0 ) { // Nothing happend, timeout
if ( job )
job - > error = JobData : : ErrTimeout ;
doQuit ( ) ;
return false ;
}
if ( ret > 0 ) {
if ( FD_ISSET ( fdPipeIn , & fdsR ) ) { // stop signal
doQuit ( ) ;
return false ;
}
if ( FD_ISSET ( tcpSocket , & fdsE ) | | FD_ISSET ( fdPipeIn , & fdsE ) ) { // broken pipe, etc
if ( job ) {
job - > result = TQString ( ) ;
resultAppend ( i18n ( " The connection is broken. " ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
if ( FD_ISSET ( tcpSocket , & fdsR ) ) // all ok
return true ;
}
if ( job ) {
job - > result = TQString ( ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
// used by sendBuffer() & connect()
bool DictAsyncClient : : waitForWrite ( )
{
fd_set fdsR , fdsW , fdsE ;
timeval tv ;
int ret ;
do {
FD_ZERO ( & fdsR ) ;
FD_SET ( fdPipeIn , & fdsR ) ;
FD_SET ( tcpSocket , & fdsR ) ;
FD_ZERO ( & fdsW ) ;
FD_SET ( tcpSocket , & fdsW ) ;
FD_ZERO ( & fdsE ) ;
FD_SET ( tcpSocket , & fdsE ) ;
FD_SET ( fdPipeIn , & fdsE ) ;
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
ret = KSocks : : self ( ) - > select ( FD_SETSIZE , & fdsR , & fdsW , & fdsE , & tv ) ;
} while ( ( ret < 0 ) & & ( errno = = EINTR ) ) ; // don't get tricked by signals
if ( ret = = - 1 ) { // select failed
if ( job ) {
job - > result = TQString ( ) ;
resultAppend ( strerror ( errno ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
if ( ret = = 0 ) { // nothing happend, timeout
if ( job )
job - > error = JobData : : ErrTimeout ;
closeSocket ( ) ;
return false ;
}
if ( ret > 0 ) {
if ( FD_ISSET ( fdPipeIn , & fdsR ) ) { // stop signal
doQuit ( ) ;
return false ;
}
if ( FD_ISSET ( tcpSocket , & fdsR ) | | FD_ISSET ( tcpSocket , & fdsE ) | | FD_ISSET ( fdPipeIn , & fdsE ) ) { // broken pipe, etc
if ( job ) {
job - > result = TQString ( ) ;
resultAppend ( i18n ( " The connection is broken. " ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
if ( FD_ISSET ( tcpSocket , & fdsW ) ) // all ok
return true ;
}
if ( job ) {
job - > result = TQString ( ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
}
// remove start/stop signal
void DictAsyncClient : : clearPipe ( )
{
fd_set fdsR ;
timeval tv ;
int selectRet ;
char buf ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
do {
FD_ZERO ( & fdsR ) ;
FD_SET ( fdPipeIn , & fdsR ) ;
if ( 1 = = ( selectRet = select ( FD_SETSIZE , & fdsR , NULL , NULL , & tv ) ) )
if ( : : read ( fdPipeIn , & buf , 1 ) = = - 1 )
: : perror ( " clearPipe() " ) ;
} while ( selectRet = = 1 ) ;
}
bool DictAsyncClient : : sendBuffer ( )
{
int ret ;
int todo = cmdBuffer . length ( ) ;
int done = 0 ;
while ( todo > 0 ) {
if ( ! waitForWrite ( ) )
return false ;
ret = KSocks : : self ( ) - > write ( tcpSocket , & cmdBuffer . data ( ) [ done ] , todo ) ;
if ( ret < = 0 ) {
if ( job ) {
job - > result = TQString ( ) ;
resultAppend ( strerror ( errno ) ) ;
job - > error = JobData : : ErrCommunication ;
}
closeSocket ( ) ;
return false ;
} else {
done + = ret ;
todo - = ret ;
}
}
return true ;
}
// set thisLine to next complete line of input
bool DictAsyncClient : : getNextLine ( )
{
thisLine = nextLine ;
nextLine = strstr ( thisLine , " \r \n " ) ;
if ( nextLine ) { // there is another full line in the inputbuffer
nextLine [ 0 ] = 0 ; // terminate string
nextLine [ 1 ] = 0 ;
nextLine + = 2 ;
return true ;
}
unsigned int div = inputEnd - thisLine + 1 ; // hmmm, I need to fetch more input from the server...
memmove ( input , thisLine , div ) ; // save last, incomplete line
thisLine = input ;
inputEnd = input + div - 1 ;
do {
if ( ( inputEnd - input ) > 9000 ) {
job - > error = JobData : : ErrMsgTooLong ;
closeSocket ( ) ;
return false ;
}
if ( ! waitForRead ( ) )
return false ;
int received ;
do {
received = KSocks : : self ( ) - > read ( tcpSocket , inputEnd , inputSize - ( inputEnd - input ) - 1 ) ;
} while ( ( received < 0 ) & & ( errno = = EINTR ) ) ; // don't get tricked by signals
if ( received < = 0 ) {
job - > result = TQString ( ) ;
resultAppend ( i18n ( " The connection is broken. " ) ) ;
job - > error = JobData : : ErrCommunication ;
closeSocket ( ) ;
return false ;
}
inputEnd + = received ;
inputEnd [ 0 ] = 0 ; // terminate *char
} while ( ! ( nextLine = strstr ( thisLine , " \r \n " ) ) ) ;
nextLine [ 0 ] = 0 ; // terminate string
nextLine [ 1 ] = 0 ;
nextLine + = 2 ;
return true ;
}
// reads next line and checks the response code
bool DictAsyncClient : : nextResponseOk ( int code )
{
if ( ! getNextLine ( ) )
return false ;
if ( strtol ( thisLine , 0L , 0 ) ! = code ) {
handleErrors ( ) ;
return false ;
}
return true ;
}
// reads next line and returns the response code
bool DictAsyncClient : : getNextResponse ( int & code )
{
if ( ! getNextLine ( ) )
return false ;
code = strtol ( thisLine , 0L , 0 ) ;
return true ;
}
void DictAsyncClient : : handleErrors ( )
{
int len = strlen ( thisLine ) ;
if ( len > 80 )
len = 80 ;
job - > result = TQString ( ) ;
resultAppend ( codec - > toUnicode ( thisLine , len ) ) ;
switch ( strtol ( thisLine , 0L , 0 ) ) {
case 420 :
case 421 :
job - > error = JobData : : ErrNotAvailable ; // server unavailable
break ;
case 500 :
case 501 :
job - > error = JobData : : ErrSyntax ; // syntax error
break ;
case 502 :
case 503 :
job - > error = JobData : : ErrCommandNotImplemented ; // command not implemented
break ;
case 530 :
job - > error = JobData : : ErrAccessDenied ; // access denied
break ;
case 531 :
job - > error = JobData : : ErrAuthFailed ; // authentication failed
break ;
case 550 :
case 551 :
job - > error = JobData : : ErrInvalidDbStrat ; // invalid strategy/database
break ;
case 554 :
job - > error = JobData : : ErrNoDatabases ; // no databases
break ;
case 555 :
job - > error = JobData : : ErrNoStrategies ; // no strategies
break ;
default :
job - > error = JobData : : ErrServerError ;
}
doQuit ( ) ;
}
void DictAsyncClient : : resultAppend ( const char * str )
{
if ( job )
job - > result + = codec - > toUnicode ( str ) ;
}
void DictAsyncClient : : resultAppend ( TQString str )
{
if ( job )
job - > result + = str ;
}
//********* DictInterface ******************************************
DictInterface : : DictInterface ( )
: newServer ( false ) , clientDoneInProgress ( false )
{
if ( : : pipe ( fdPipeIn ) = = - 1 ) {
perror ( " Creating in pipe " ) ;
KMessageBox : : error ( global - > topLevel , i18n ( " Internal error: \n Failed to open pipes for internal communication. " ) ) ;
kapp - > exit ( 1 ) ;
}
if ( : : pipe ( fdPipeOut ) = = - 1 ) {
perror ( " Creating out pipe " ) ;
KMessageBox : : error ( global - > topLevel , i18n ( " Internal error: \n Failed to open pipes for internal communication. " ) ) ;
kapp - > exit ( 1 ) ;
}
if ( - 1 = = fcntl ( fdPipeIn [ 0 ] , F_SETFL , O_NONBLOCK ) ) { // make socket non-blocking
perror ( " fcntl() " ) ;
KMessageBox : : error ( global - > topLevel , i18n ( " Internal error: \n Failed to open pipes for internal communication. " ) ) ;
kapp - > exit ( 1 ) ;
}
if ( - 1 = = fcntl ( fdPipeOut [ 0 ] , F_SETFL , O_NONBLOCK ) ) { // make socket non-blocking
perror ( " fcntl() " ) ;
KMessageBox : : error ( global - > topLevel , i18n ( " Internal error: \n Failed to open pipes for internal communication. " ) ) ;
kapp - > exit ( 1 ) ;
}
notifier = new TQSocketNotifier ( fdPipeIn [ 0 ] , TQSocketNotifier : : Read , this ) ;
connect ( notifier , TQT_SIGNAL ( activated ( int ) ) , this , TQT_SLOT ( clientDone ( ) ) ) ;
// initialize the KSocks stuff in the main thread, otherwise we get
// strange effects on FreeBSD
( void ) KSocks : : self ( ) ;
client = new DictAsyncClient ( fdPipeOut [ 0 ] , fdPipeIn [ 1 ] ) ;
if ( 0 ! = pthread_create ( & threadID , 0 , & ( client - > startThread ) , client ) ) {
KMessageBox : : error ( global - > topLevel , i18n ( " Internal error: \n Unable to create thread. " ) ) ;
kapp - > exit ( 1 ) ;
}
jobList . setAutoDelete ( true ) ;
}
DictInterface : : ~ DictInterface ( )
{
disconnect ( notifier , TQT_SIGNAL ( activated ( int ) ) , this , TQT_SLOT ( clientDone ( ) ) ) ;
if ( 0 ! = pthread_cancel ( threadID ) )
kdWarning ( ) < < " pthread_cancel failed! " < < endl ;
if ( 0 ! = pthread_join ( threadID , NULL ) )
kdWarning ( ) < < " pthread_join failed! " < < endl ;
delete client ;
if ( : : close ( fdPipeIn [ 0 ] ) = = - 1 ) {
perror ( " Closing fdPipeIn[0] " ) ;
}
if ( : : close ( fdPipeIn [ 1 ] ) = = - 1 ) {
perror ( " Closing fdPipeIn[1] " ) ;
}
if ( : : close ( fdPipeOut [ 0 ] ) = = - 1 ) {
perror ( " Closing fdPipeOut[0] " ) ;
}
if ( : : close ( fdPipeOut [ 1 ] ) = = - 1 ) {
perror ( " Closing fdPipeOut[1] " ) ;
}
}
// inform the client when server settings get changed
void DictInterface : : serverChanged ( )
{
newServer = true ;
}
// cancel all pending jobs
void DictInterface : : stop ( )
{
if ( jobList . isEmpty ( ) ) {
return ;
} else {
while ( jobList . count ( ) > 1 ) // not yet started jobs can be deleted directly
jobList . removeLast ( ) ;
if ( ! clientDoneInProgress ) {
jobList . getFirst ( ) - > canceled = true ; // clientDone() now ignores the results of this job
char buf ; // write one char in the pipe to the async thread
if ( : : write ( fdPipeOut [ 1 ] , & buf , 1 ) = = - 1 )
: : perror ( " stop() " ) ;
}
}
}
void DictInterface : : define ( const TQString & query )
{
JobData * newJob = generateQuery ( JobData : : TDefine , query ) ;
if ( newJob )
insertJob ( newJob ) ;
}
void DictInterface : : getDefinitions ( TQStringList query )
{
JobData * newjob = new JobData ( JobData : : TGetDefinitions , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ;
newjob - > defines = query ;
newServer = false ;
insertJob ( newjob ) ;
}
void DictInterface : : match ( const TQString & query )
{
JobData * newJob = generateQuery ( JobData : : TMatch , query ) ;
if ( newJob ) {
if ( global - > currentStrategy = = 0 )
newJob - > strategy = " . " ; // spell check strategy
else
newJob - > strategy = global - > strategies [ global - > currentStrategy ] . utf8 ( ) ;
insertJob ( newJob ) ;
}
}
// fetch detailed db info
void DictInterface : : showDbInfo ( const TQString & db )
{
TQString ndb = db . simplifyWhiteSpace ( ) ; // cleanup query string
if ( ndb . isEmpty ( ) )
return ;
if ( ndb . length ( ) > 100 ) // shorten if necessary
ndb . truncate ( 100 ) ;
JobData * newjob = new JobData ( JobData : : TShowDbInfo , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ;
newServer = false ;
newjob - > query = ndb ; // construct job...
insertJob ( newjob ) ;
}
void DictInterface : : showDatabases ( )
{
insertJob ( new JobData ( JobData : : TShowDatabases , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ) ;
newServer = false ;
}
void DictInterface : : showStrategies ( )
{
insertJob ( new JobData ( JobData : : TShowStrategies , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ) ;
newServer = false ;
}
void DictInterface : : showInfo ( )
{
insertJob ( new JobData ( JobData : : TShowInfo , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ) ;
newServer = false ;
}
// get info about databases & stratgies the server knows
void DictInterface : : updateServer ( )
{
insertJob ( new JobData ( JobData : : TUpdate , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ) ;
newServer = false ;
}
// client-thread ended
void DictInterface : : clientDone ( )
{
TQString message ;
cleanPipes ( ) ; // read from pipe so that notifier doesn<73> t fire again
if ( jobList . isEmpty ( ) ) {
kdDebug ( 5004 ) < < " This shouldn<64> t happen, the client-thread signaled termination, but the job list is empty " < < endl ;
return ; // strange..
}
clientDoneInProgress = true ;
TQStringList : : iterator it ;
JobData * job = jobList . getFirst ( ) ;
if ( ! job - > canceled ) { // non-interupted job?
if ( JobData : : ErrNoErr = = job - > error ) {
switch ( job - > type ) {
case JobData : : TUpdate :
global - > serverDatabases . clear ( ) ;
for ( it = job - > databases . begin ( ) ; it ! = job - > databases . end ( ) ; + + it )
global - > serverDatabases . append ( * it ) ;
global - > databases = global - > serverDatabases ;
for ( int i = global - > databaseSets . count ( ) - 1 ; i > = 0 ; i - - )
global - > databases . prepend ( global - > databaseSets . at ( i ) - > first ( ) ) ;
global - > databases . prepend ( i18n ( " All Databases " ) ) ;
global - > currentDatabase = 0 ;
global - > strategies . clear ( ) ;
for ( it = job - > strategies . begin ( ) ; it ! = job - > strategies . end ( ) ; + + it )
global - > strategies . append ( * it ) ;
global - > strategies . prepend ( i18n ( " Spell Check " ) ) ;
global - > currentStrategy = 0 ;
message = i18n ( " Received database/strategy list " ) ;
emit stopped ( message ) ;
emit infoReady ( ) ;
break ;
case JobData : : TDefine :
case JobData : : TGetDefinitions :
if ( job - > type = = JobData : : TDefine ) {
switch ( job - > numFetched ) {
case 0 :
message = i18n ( " No definitions found " ) ;
break ;
case 1 :
message = i18n ( " One definition found " ) ;
break ;
default :
message = i18n ( " %1 definitions found " ) . tqarg ( job - > numFetched ) ;
}
} else {
switch ( job - > numFetched ) {
case 0 :
message = i18n ( " No definitions fetched " ) ;
break ;
case 1 :
message = i18n ( " One definition fetched " ) ;
break ;
default :
message = i18n ( " %1 definitions fetched " ) . tqarg ( job - > numFetched ) ;
}
}
emit stopped ( message ) ;
emit resultReady ( job - > result , job - > query ) ;
break ;
case JobData : : TMatch :
switch ( job - > numFetched ) {
case 0 :
message = i18n ( " No matching definitions found " ) ;
break ;
case 1 :
message = i18n ( " One matching definition found " ) ;
break ;
default :
message = i18n ( " %1 matching definitions found " ) . tqarg ( job - > numFetched ) ;
}
emit stopped ( message ) ;
emit matchReady ( job - > matches ) ;
break ;
default :
message = i18n ( " Received information " ) ;
emit stopped ( message ) ;
emit resultReady ( job - > result , job - > query ) ;
}
} else {
TQString errMsg ;
switch ( job - > error ) {
case JobData : : ErrCommunication :
errMsg = i18n ( " Communication error: \n \n " ) ;
errMsg + = job - > result ;
break ;
case JobData : : ErrTimeout :
errMsg = i18n ( " A delay occurred which exceeded the \n current timeout limit of %1 seconds. \n You can modify this limit in the Preferences Dialog. " ) . tqarg ( global - > timeout ) ;
break ;
case JobData : : ErrBadHost :
errMsg = i18n ( " Unable to connect to: \n %1:%2 \n \n Cannot resolve hostname. " ) . tqarg ( job - > server ) . tqarg ( job - > port ) ;
break ;
case JobData : : ErrConnect :
errMsg = i18n ( " Unable to connect to: \n %1:%2 \n \n " ) . tqarg ( job - > server ) . tqarg ( job - > port ) ;
errMsg + = job - > result ;
break ;
case JobData : : ErrRefused :
errMsg = i18n ( " Unable to connect to: \n %1:%2 \n \n The server refused the connection. " ) . tqarg ( job - > server ) . tqarg ( job - > port ) ;
break ;
case JobData : : ErrNotAvailable :
errMsg = i18n ( " The server is temporarily unavailable. " ) ;
break ;
case JobData : : ErrSyntax :
errMsg = i18n ( " The server reported a syntax error. \n This shouldn't happen -- please consider \n writing a bug report. " ) ;
break ;
case JobData : : ErrCommandNotImplemented :
errMsg = i18n ( " A command that Kdict needs isn't \n implemented on the server. " ) ;
break ;
case JobData : : ErrAccessDenied :
errMsg = i18n ( " Access denied. \n This host is not allowed to connect. " ) ;
break ;
case JobData : : ErrAuthFailed :
errMsg = i18n ( " Authentication failed. \n Please enter a valid username and password. " ) ;
break ;
case JobData : : ErrInvalidDbStrat :
errMsg = i18n ( " Invalid database/strategy. \n You probably need to use Server->Get Capabilities. " ) ;
break ;
case JobData : : ErrNoDatabases :
errMsg = i18n ( " No databases available. \n It is possible that you need to authenticate \n with a valid username/password combination to \n gain access to any databases. " ) ;
break ;
case JobData : : ErrNoStrategies :
errMsg = i18n ( " No strategies available. " ) ;
break ;
case JobData : : ErrServerError :
errMsg = i18n ( " The server sent an unexpected reply: \n \" %1 \" \n This shouldn't happen, please consider \n writing a bug report " ) . tqarg ( job - > result ) ;
break ;
case JobData : : ErrMsgTooLong :
errMsg = i18n ( " The server sent a response with a text line \n that was too long. \n (RFC 2229: max. 1024 characters/6144 octets) " ) ;
break ;
case JobData : : ErrNoErr : // make compiler happy
errMsg = i18n ( " No Errors " ) ;
}
message = i18n ( " Error " ) ;
emit stopped ( message ) ;
KMessageBox : : error ( global - > topLevel , errMsg ) ;
}
} else {
message = i18n ( " Stopped " ) ;
emit stopped ( message ) ;
}
clientDoneInProgress = false ;
client - > removeJob ( ) ;
jobList . removeFirst ( ) ; // this job is now history
if ( ! jobList . isEmpty ( ) ) // work to be done?
startClient ( ) ; // => restart client
}
JobData * DictInterface : : generateQuery ( JobData : : QueryType type , TQString query )
{
query = query . simplifyWhiteSpace ( ) ; // cleanup query string
if ( query . isEmpty ( ) )
return 0L ;
if ( query . length ( ) > 300 ) // shorten if necessary
query . truncate ( 300 ) ;
query = query . replace ( TQRegExp ( " [ \" \\ ] " ) , " " ) ; // remove remaining illegal chars...
if ( query . isEmpty ( ) )
return 0L ;
JobData * newjob = new JobData ( type , newServer , global - > server , global - > port ,
global - > idleHold , global - > timeout , global - > pipeSize , global - > encoding , global - > authEnabled ,
global - > user , global - > secret , global - > headLayout ) ;
newServer = false ;
newjob - > query = query ; // construct job...
if ( global - > currentDatabase = = 0 ) // all databases
newjob - > databases . append ( " * " ) ;
else {
if ( ( global - > currentDatabase > 0 ) & & // database set
( global - > currentDatabase < global - > databaseSets . count ( ) + 1 ) ) {
for ( int i = 0 ; i < ( int ) global - > serverDatabases . count ( ) ; i + + )
if ( ( global - > databaseSets . at ( global - > currentDatabase - 1 ) ) - > findIndex ( global - > serverDatabases [ i ] ) > 0 )
newjob - > databases . append ( global - > serverDatabases [ i ] . utf8 ( ) . data ( ) ) ;
if ( newjob - > databases . count ( ) = = 0 ) {
KMessageBox : : sorry ( global - > topLevel , i18n ( " Please select at least one database. " ) ) ;
delete newjob ;
return 0L ;
}
} else { // one database
newjob - > databases . append ( global - > databases [ global - > currentDatabase ] . utf8 ( ) . data ( ) ) ;
}
}
return newjob ;
}
void DictInterface : : insertJob ( JobData * job )
{
if ( jobList . isEmpty ( ) ) { // Client has nothing to do, start directly
jobList . append ( job ) ;
startClient ( ) ;
} else { // there are other pending jobs...
stop ( ) ;
jobList . append ( job ) ;
}
}
// start client-thread
void DictInterface : : startClient ( )
{
cleanPipes ( ) ;
if ( jobList . isEmpty ( ) ) {
kdDebug ( 5004 ) < < " This shouldn<64> t happen, startClient called, but clientList is empty " < < endl ;
return ;
}
client - > insertJob ( jobList . getFirst ( ) ) ;
char buf ; // write one char in the pipe to the async thread
if ( : : write ( fdPipeOut [ 1 ] , & buf , 1 ) = = - 1 )
: : perror ( " startClient() " ) ;
TQString message ;
switch ( jobList . getFirst ( ) - > type ) {
case JobData : : TDefine :
case JobData : : TGetDefinitions :
case JobData : : TMatch :
message = i18n ( " Querying server... " ) ;
break ;
case JobData : : TShowDatabases :
case JobData : : TShowStrategies :
case JobData : : TShowInfo :
case JobData : : TShowDbInfo :
message = i18n ( " Fetching information... " ) ;
break ;
case JobData : : TUpdate :
message = i18n ( " Updating server information... " ) ;
break ;
}
emit started ( message ) ;
}
// empty the pipes, so that notifier stops firing
void DictInterface : : cleanPipes ( )
{
fd_set rfds ;
struct timeval tv ;
int ret ;
char buf ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
do {
FD_ZERO ( & rfds ) ;
FD_SET ( fdPipeIn [ 0 ] , & rfds ) ;
if ( 1 = = ( ret = select ( FD_SETSIZE , & rfds , NULL , NULL , & tv ) ) )
if ( : : read ( fdPipeIn [ 0 ] , & buf , 1 ) = = - 1 )
: : perror ( " cleanPipes " ) ;
} while ( ret = = 1 ) ;
do {
FD_ZERO ( & rfds ) ;
FD_SET ( fdPipeOut [ 0 ] , & rfds ) ;
if ( 1 = = ( ret = select ( FD_SETSIZE , & rfds , NULL , NULL , & tv ) ) )
if ( : : read ( fdPipeOut [ 0 ] , & buf , 1 ) = = - 1 )
: : perror ( " cleanPipes " ) ;
} while ( ret = = 1 ) ;
}
//--------------------------------
# include "dict.moc"