source: trunk/examples/network/networkprotocol/nntp.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 7.4 KB
Line 
1/****************************************************************************
2** $Id: nntp.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
5**
6** This file is part of an example program for Qt. This example
7** program may be used, distributed and modified without limitation.
8**
9*****************************************************************************/
10
11#include "nntp.h"
12#include <qurlinfo.h>
13#include <stdlib.h>
14#include <qurloperator.h>
15#include <qstringlist.h>
16#include <qregexp.h>
17
18Nntp::Nntp()
19 : QNetworkProtocol(), connectionReady( FALSE ),
20 readGroups( FALSE ), readArticle( FALSE )
21{
22 // create the command socket and connect to its signals
23 commandSocket = new QSocket( this );
24 connect( commandSocket, SIGNAL( hostFound() ),
25 this, SLOT( hostFound() ) );
26 connect( commandSocket, SIGNAL( connected() ),
27 this, SLOT( connected() ) );
28 connect( commandSocket, SIGNAL( connectionClosed() ),
29 this, SLOT( closed() ) );
30 connect( commandSocket, SIGNAL( readyRead() ),
31 this, SLOT( readyRead() ) );
32 connect( commandSocket, SIGNAL( error( int ) ),
33 this, SLOT( error( int ) ) );
34}
35
36Nntp::~Nntp()
37{
38 close();
39 delete commandSocket;
40}
41
42void Nntp::operationListChildren( QNetworkOperation * )
43{
44 // create a command
45 QString path = url()->path(), cmd;
46 if ( path.isEmpty() || path == "/" ) {
47 // if the path is empty or we are in the root dir,
48 // we want to read the list of available newsgroups
49 cmd = "list newsgroups\r\n";
50 } else if ( url()->isDir() ) {
51 // if the path is a directory (in our case a news group)
52 // we want to list the articles of this group
53 path = path.replace( "/", "" );
54 cmd = "listgroup " + path + "\r\n";
55 } else
56 return;
57
58 // write the command to the socket
59 commandSocket->writeBlock( cmd.latin1(), cmd.length() );
60 readGroups = TRUE;
61}
62
63void Nntp::operationGet( QNetworkOperation *op )
64{
65 // get the dirPath of the URL (this is our news group)
66 // and the filename (which is the article we want to read)
67 QUrl u( op->arg( 0 ) );
68 QString dirPath = u.dirPath(), file = u.fileName();
69 dirPath = dirPath.replace( "/", "" );
70
71 // go to the group in which the article is
72 QString cmd;
73 cmd = "group " + dirPath + "\r\n";
74 commandSocket->writeBlock( cmd.latin1(), cmd.length() );
75
76 // read the head of the article
77 cmd = "article " + file + "\r\n";
78 commandSocket->writeBlock( cmd.latin1(), cmd.length() );
79 readArticle = TRUE;
80}
81
82bool Nntp::checkConnection( QNetworkOperation * )
83{
84 // we are connected, return TRUE
85 if ( commandSocket->isOpen() && connectionReady )
86 return TRUE;
87
88 // seems that there is no chance to connect
89 if ( commandSocket->isOpen() )
90 return FALSE;
91
92 // don't call connectToHost() if we are already trying to connect
93 if ( commandSocket->state() == QSocket::Connecting )
94 return FALSE;
95
96 // start connecting
97 connectionReady = FALSE;
98 commandSocket->connectToHost( url()->host(),
99 url()->port() != -1 ? url()->port() : 119 );
100 return FALSE;
101}
102
103void Nntp::close()
104{
105 // close the command socket
106 if ( commandSocket->isOpen() ) {
107 commandSocket->writeBlock( "quit\r\n", strlen( "quit\r\n" ) );
108 commandSocket->close();
109 }
110}
111
112int Nntp::supportedOperations() const
113{
114 // we only support listing children and getting data
115 return OpListChildren | OpGet;
116}
117
118void Nntp::hostFound()
119{
120 if ( url() )
121 emit connectionStateChanged( ConHostFound, tr( "Host %1 found" ).arg( url()->host() ) );
122 else
123 emit connectionStateChanged( ConHostFound, tr( "Host found" ) );
124}
125
126void Nntp::connected()
127{
128 if ( url() )
129 emit connectionStateChanged( ConConnected, tr( "Connected to host %1" ).arg( url()->host() ) );
130 else
131 emit connectionStateChanged( ConConnected, tr( "Connected to host" ) );
132}
133
134void Nntp::closed()
135{
136 if ( url() )
137 emit connectionStateChanged( ConClosed, tr( "Connection to %1 closed" ).arg( url()->host() ) );
138 else
139 emit connectionStateChanged( ConClosed, tr( "Connection closed" ) );
140}
141
142void Nntp::readyRead()
143{
144 // new data arrived on the command socket
145
146 // of we should read the list of available groups, let's do so
147 if ( readGroups ) {
148 parseGroups();
149 return;
150 }
151
152 // of we should read an article, let's do so
153 if ( readArticle ) {
154 parseArticle();
155 return;
156 }
157
158 // read the new data from the socket
159 QCString s;
160 s.resize( commandSocket->bytesAvailable() );
161 commandSocket->readBlock( s.data(), commandSocket->bytesAvailable() );
162
163 if ( !url() )
164 return;
165
166 // of the code of the server response was 200, we know that the
167 // server is ready to get commands from us now
168 if ( s.left( 3 ) == "200" )
169 connectionReady = TRUE;
170}
171
172void Nntp::parseGroups()
173{
174 if ( !commandSocket->canReadLine() )
175 return;
176
177 // read one line after the other
178 while ( commandSocket->canReadLine() ) {
179 QString s = commandSocket->readLine();
180
181 // if the line starts with a dot, all groups or articles have been listed,
182 // so we finished processing the listChildren() command
183 if ( s[ 0 ] == '.' ) {
184 readGroups = FALSE;
185 operationInProgress()->setState( StDone );
186 emit finished( operationInProgress() );
187 return;
188 }
189
190 // if the code of the server response is 215 or 211
191 // the next line will be the first group or article (depending on what we read).
192 // So let others know that we start reading now...
193 if ( s.left( 3 ) == "215" || s.left( 3 ) == "211" ) {
194 operationInProgress()->setState( StInProgress );
195 emit start( operationInProgress() );
196 continue;
197 }
198
199 // parse the line and create a QUrlInfo object
200 // which describes the child (group or article)
201 bool tab = s.find( '\t' ) != -1;
202 QString group = s.mid( 0, s.find( tab ? '\t' : ' ' ) );
203 QUrlInfo inf;
204 inf.setName( group );
205 QString path = url()->path();
206 inf.setDir( path.isEmpty() || path == "/" );
207 inf.setSymLink( FALSE );
208 inf.setFile( !inf.isDir() );
209 inf.setWritable( FALSE );
210 inf.setReadable( TRUE );
211
212 // let others know about our new child
213 emit newChild( inf, operationInProgress() );
214 }
215
216}
217
218void Nntp::parseArticle()
219{
220 if ( !commandSocket->canReadLine() )
221 return;
222
223 // read an article one line after the other
224 while ( commandSocket->canReadLine() ) {
225 QString s = commandSocket->readLine();
226
227 // if the line starts with a dot, we finished reading something
228 if ( s[ 0 ] == '.' ) {
229 readArticle = FALSE;
230 operationInProgress()->setState( StDone );
231 emit finished( operationInProgress() );
232 return;
233 }
234
235 if ( s.right( 1 ) == "\n" )
236 s.remove( s.length() - 1, 1 );
237
238 // emit the new data of the article which we read
239 emit data( QCString( s.ascii() ), operationInProgress() );
240 }
241}
242
243void Nntp::error( int code )
244{
245 if ( code == QSocket::ErrHostNotFound ||
246 code == QSocket::ErrConnectionRefused ) {
247 // this signal is called if connecting to the server failed
248 if ( operationInProgress() ) {
249 QString msg = tr( "Host not found or couldn't connect to: \n" + url()->host() );
250 operationInProgress()->setState( StFailed );
251 operationInProgress()->setProtocolDetail( msg );
252 operationInProgress()->setErrorCode( (int)ErrHostNotFound );
253 clearOperationQueue();
254 emit finished( operationInProgress() );
255 }
256 }
257}
Note: See TracBrowser for help on using the repository browser.