You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
7.1 KiB
257 lines
7.1 KiB
14 years ago
|
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
||
|
**
|
||
|
** This file is part of an example program for Qt. This example
|
||
|
** program may be used, distributed and modified without limitation.
|
||
|
**
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include "nntp.h"
|
||
|
#include <qurlinfo.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <qurloperator.h>
|
||
|
#include <qstringlist.h>
|
||
|
#include <qregexp.h>
|
||
|
|
||
|
Nntp::Nntp()
|
||
|
: QNetworkProtocol(), connectionReady( FALSE ),
|
||
|
readGroups( FALSE ), readArticle( FALSE )
|
||
|
{
|
||
|
// create the command socket and connect to its signals
|
||
|
commandSocket = new QSocket( this );
|
||
|
connect( commandSocket, SIGNAL( hostFound() ),
|
||
|
this, SLOT( hostFound() ) );
|
||
|
connect( commandSocket, SIGNAL( connected() ),
|
||
|
this, SLOT( connected() ) );
|
||
|
connect( commandSocket, SIGNAL( connectionClosed() ),
|
||
|
this, SLOT( closed() ) );
|
||
|
connect( commandSocket, SIGNAL( readyRead() ),
|
||
|
this, SLOT( readyRead() ) );
|
||
|
connect( commandSocket, SIGNAL( error( int ) ),
|
||
|
this, SLOT( error( int ) ) );
|
||
|
}
|
||
|
|
||
|
Nntp::~Nntp()
|
||
|
{
|
||
|
close();
|
||
|
delete commandSocket;
|
||
|
}
|
||
|
|
||
|
void Nntp::operationListChildren( QNetworkOperation * )
|
||
|
{
|
||
|
// create a command
|
||
|
QString path = url()->path(), cmd;
|
||
|
if ( path.isEmpty() || path == "/" ) {
|
||
|
// if the path is empty or we are in the root dir,
|
||
|
// we want to read the list of available newsgroups
|
||
|
cmd = "list newsgroups\r\n";
|
||
|
} else if ( url()->isDir() ) {
|
||
|
// if the path is a directory (in our case a news group)
|
||
|
// we want to list the articles of this group
|
||
|
path = path.replace( "/", "" );
|
||
|
cmd = "listgroup " + path + "\r\n";
|
||
|
} else
|
||
|
return;
|
||
|
|
||
|
// write the command to the socket
|
||
|
commandSocket->writeBlock( cmd.latin1(), cmd.length() );
|
||
|
readGroups = TRUE;
|
||
|
}
|
||
|
|
||
|
void Nntp::operationGet( QNetworkOperation *op )
|
||
|
{
|
||
|
// get the dirPath of the URL (this is our news group)
|
||
|
// and the filename (which is the article we want to read)
|
||
|
QUrl u( op->arg( 0 ) );
|
||
|
QString dirPath = u.dirPath(), file = u.fileName();
|
||
|
dirPath = dirPath.replace( "/", "" );
|
||
|
|
||
|
// go to the group in which the article is
|
||
|
QString cmd;
|
||
|
cmd = "group " + dirPath + "\r\n";
|
||
|
commandSocket->writeBlock( cmd.latin1(), cmd.length() );
|
||
|
|
||
|
// read the head of the article
|
||
|
cmd = "article " + file + "\r\n";
|
||
|
commandSocket->writeBlock( cmd.latin1(), cmd.length() );
|
||
|
readArticle = TRUE;
|
||
|
}
|
||
|
|
||
|
bool Nntp::checkConnection( QNetworkOperation * )
|
||
|
{
|
||
|
// we are connected, return TRUE
|
||
|
if ( commandSocket->isOpen() && connectionReady )
|
||
|
return TRUE;
|
||
|
|
||
|
// seems that there is no chance to connect
|
||
|
if ( commandSocket->isOpen() )
|
||
|
return FALSE;
|
||
|
|
||
|
// don't call connectToHost() if we are already trying to connect
|
||
|
if ( commandSocket->state() == QSocket::Connecting )
|
||
|
return FALSE;
|
||
|
|
||
|
// start connecting
|
||
|
connectionReady = FALSE;
|
||
|
commandSocket->connectToHost( url()->host(),
|
||
|
url()->port() != -1 ? url()->port() : 119 );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void Nntp::close()
|
||
|
{
|
||
|
// close the command socket
|
||
|
if ( commandSocket->isOpen() ) {
|
||
|
commandSocket->writeBlock( "quit\r\n", strlen( "quit\r\n" ) );
|
||
|
commandSocket->close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int Nntp::supportedOperations() const
|
||
|
{
|
||
|
// we only support listing children and getting data
|
||
|
return OpListChildren | OpGet;
|
||
|
}
|
||
|
|
||
|
void Nntp::hostFound()
|
||
|
{
|
||
|
if ( url() )
|
||
|
emit connectionStateChanged( ConHostFound, tr( "Host %1 found" ).arg( url()->host() ) );
|
||
|
else
|
||
|
emit connectionStateChanged( ConHostFound, tr( "Host found" ) );
|
||
|
}
|
||
|
|
||
|
void Nntp::connected()
|
||
|
{
|
||
|
if ( url() )
|
||
|
emit connectionStateChanged( ConConnected, tr( "Connected to host %1" ).arg( url()->host() ) );
|
||
|
else
|
||
|
emit connectionStateChanged( ConConnected, tr( "Connected to host" ) );
|
||
|
}
|
||
|
|
||
|
void Nntp::closed()
|
||
|
{
|
||
|
if ( url() )
|
||
|
emit connectionStateChanged( ConClosed, tr( "Connection to %1 closed" ).arg( url()->host() ) );
|
||
|
else
|
||
|
emit connectionStateChanged( ConClosed, tr( "Connection closed" ) );
|
||
|
}
|
||
|
|
||
|
void Nntp::readyRead()
|
||
|
{
|
||
|
// new data arrived on the command socket
|
||
|
|
||
|
// of we should read the list of available groups, let's do so
|
||
|
if ( readGroups ) {
|
||
|
parseGroups();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// of we should read an article, let's do so
|
||
|
if ( readArticle ) {
|
||
|
parseArticle();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// read the new data from the socket
|
||
|
QCString s;
|
||
|
s.resize( commandSocket->bytesAvailable() + 1 );
|
||
|
commandSocket->readBlock( s.data(), commandSocket->bytesAvailable() );
|
||
|
|
||
|
if ( !url() )
|
||
|
return;
|
||
|
|
||
|
// of the code of the server response was 200, we know that the
|
||
|
// server is ready to get commands from us now
|
||
|
if ( s.left( 3 ) == "200" )
|
||
|
connectionReady = TRUE;
|
||
|
}
|
||
|
|
||
|
void Nntp::parseGroups()
|
||
|
{
|
||
|
if ( !commandSocket->canReadLine() )
|
||
|
return;
|
||
|
|
||
|
// read one line after the other
|
||
|
while ( commandSocket->canReadLine() ) {
|
||
|
QString s = commandSocket->readLine();
|
||
|
|
||
|
// if the line starts with a dot, all groups or articles have been listed,
|
||
|
// so we finished processing the listChildren() command
|
||
|
if ( s[ 0 ] == '.' ) {
|
||
|
readGroups = FALSE;
|
||
|
operationInProgress()->setState( StDone );
|
||
|
emit finished( operationInProgress() );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// if the code of the server response is 215 or 211
|
||
|
// the next line will be the first group or article (depending on what we read).
|
||
|
// So let others know that we start reading now...
|
||
|
if ( s.left( 3 ) == "215" || s.left( 3 ) == "211" ) {
|
||
|
operationInProgress()->setState( StInProgress );
|
||
|
emit start( operationInProgress() );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// parse the line and create a QUrlInfo object
|
||
|
// which describes the child (group or article)
|
||
|
bool tab = s.find( '\t' ) != -1;
|
||
|
QString group = s.mid( 0, s.find( tab ? '\t' : ' ' ) );
|
||
|
QUrlInfo inf;
|
||
|
inf.setName( group );
|
||
|
QString path = url()->path();
|
||
|
inf.setDir( path.isEmpty() || path == "/" );
|
||
|
inf.setSymLink( FALSE );
|
||
|
inf.setFile( !inf.isDir() );
|
||
|
inf.setWritable( FALSE );
|
||
|
inf.setReadable( TRUE );
|
||
|
|
||
|
// let others know about our new child
|
||
|
emit newChild( inf, operationInProgress() );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void Nntp::parseArticle()
|
||
|
{
|
||
|
if ( !commandSocket->canReadLine() )
|
||
|
return;
|
||
|
|
||
|
// read an article one line after the other
|
||
|
while ( commandSocket->canReadLine() ) {
|
||
|
QString s = commandSocket->readLine();
|
||
|
|
||
|
// if the line starts with a dot, we finished reading something
|
||
|
if ( s[ 0 ] == '.' ) {
|
||
|
readArticle = FALSE;
|
||
|
operationInProgress()->setState( StDone );
|
||
|
emit finished( operationInProgress() );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( s.right( 1 ) == "\n" )
|
||
|
s.remove( s.length() - 1, 1 );
|
||
|
|
||
|
// emit the new data of the article which we read
|
||
|
emit data( QCString( s.ascii() ), operationInProgress() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Nntp::error( int code )
|
||
|
{
|
||
|
if ( code == QSocket::ErrHostNotFound ||
|
||
|
code == QSocket::ErrConnectionRefused ) {
|
||
|
// this signal is called if connecting to the server failed
|
||
|
if ( operationInProgress() ) {
|
||
|
QString msg = tr( "Host not found or couldn't connect to: \n" + url()->host() );
|
||
|
operationInProgress()->setState( StFailed );
|
||
|
operationInProgress()->setProtocolDetail( msg );
|
||
|
operationInProgress()->setErrorCode( (int)ErrHostNotFound );
|
||
|
clearOperationQueue();
|
||
|
emit finished( operationInProgress() );
|
||
|
}
|
||
|
}
|
||
|
}
|