OSDN Git Service

>>800
[kita/kita.git] / kita / src / libkita / access.cpp
1 /***************************************************************************
2 *   Copyright (C) 2003 by Hideki Ikemoto                                  *
3 *   ikemo@wakaba.jp                                                       *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 ***************************************************************************/
10 #include "access.h"
11
12 #include "thread.h"
13 #include "cache.h"
14 #include "threadinfo.h"
15
16 #include <config.h>
17
18 #include <sys/stat.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21
22 #include <kurl.h>
23 #include <kglobal.h>
24 #include <kstandarddirs.h>
25 #include <kprotocolmanager.h>
26
27 #include <kio/slaveconfig.h>
28 #include <kio/netaccess.h>
29 #include <kio/jobclasses.h>
30 #include <kio/job.h>
31
32 #include <qregexp.h>
33 #include <qfile.h>
34 #include <qmessagebox.h>
35
36 using namespace Kita;
37
38 // copied from http.cc
39 // ¥­¥ã¥Ã¥·¥å¤¬¤¢¤ë¤È¤­¤Ï¤½¤ÎÆâÍƤòmalloc¤·¤¿Îΰè¤Ë¥³¥Ô¡¼¤·¤ÆÊÖ¤¹¡£
40 // ¥­¥ã¥Ã¥·¥å¤¬¤Ê¤¤¤È¤­¤Ï0¤òÊÖ¤¹¡£
41 QCString Access::getCacheData( const KURL& url )
42 {
43     QString cachePath = Kita::Cache::getPath( url );
44
45     FILE *fs = fopen( QFile::encodeName( cachePath ), "r" );
46     if ( !fs ) {
47         return 0;
48     }
49
50     struct stat buf;
51     ::stat( QFile::encodeName( cachePath ), &buf );
52     int pos = ftell( fs );
53     int datasize = buf.st_size - pos;
54
55     char* ret = static_cast<char *>( malloc( datasize + 1 ) );
56     fread( ret, datasize, 1, fs );
57     ret[ datasize ] = '\0';
58     fclose( fs );
59     return ret;
60 }
61
62 // ¥­¥ã¥Ã¥·¥å¤Ë½ñ¤­¹þ¤ß¡£
63 // partial data¤¬Æþ¤Ã¤Æ¤ë¤Î¤Ç¤½¤ì¤ò½ñ¤­´¹¤¨¤ë¡£
64 void Access::writeCacheData( const KURL& url )
65 {
66     if ( m_orgData.isNull() && responseCode() == 304 ) {
67         m_threadData = QString::null;
68         m_orgData = m_threadData;
69         return ;
70     } else if ( ! m_orgData.isNull() && responseCode() == 304 ) {
71         m_threadData = m_orgData;
72         return ;
73     } else if ( ! m_orgData.isNull() && responseCode() == 206 ) {
74         m_threadData = m_orgData + m_threadData;
75     }
76     m_orgData = m_threadData;
77
78     QString cachePath = Kita::Cache::getPath( url );
79     FILE *fs = fopen( QFile::encodeName( cachePath ), "w" );
80     if ( !fs ) return ;
81
82     fwrite( m_threadData, m_threadData.length(), 1, fs );
83     fclose( fs );
84
85     return ;
86 }
87
88 QString Access::getupdate()
89 {
90
91     QString retstr;
92     m_threadData = "";
93     m_firstReceive = FALSE;
94
95     if ( KURL( m_thread->datURL() ).protocol() != "k2ch" ) {
96         KIO::SlaveConfig::self() ->setConfigData( "http",
97                 KURL( m_thread->datURL() ).host(),
98                 "UserAgent",
99                 QString( "Monazilla/1.00 (Kita/%1)" ).arg( VERSION ) );
100     }
101
102     KIO::TransferJob* job = KIO::get( m_thread->datURL(), true, false );
103     m_currentJob = job;
104
105     connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
106              SLOT( slotReceiveThreadData( KIO::Job*, const QByteArray& ) ) );
107     connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( slotThreadResult( KIO::Job* ) ) );
108
109     // use 'HTTP-Headers' metadata.
110     job->addMetaData( "PropagateHttpHeader", "true" );
111     if ( ! m_orgData.isNull() ) {
112         m_firstReceive = TRUE; /* remove first char. see also slotReceiveThreadData() */
113         job->addMetaData( "resume", QString::number( m_orgData.length() - 1 ) );
114         job->addMetaData( "AllowCompressedPage", "false" );
115     }
116
117     return QString::null; /* dummy */
118 }
119
120 void Access::slotThreadResult( KIO::Job* job )
121 {
122     QString retstr;
123     
124     m_currentJob = 0;
125     if ( job->error() ) {
126         job->showErrorDialog();
127     } else {
128         m_header = job->queryMetaData( "HTTP-Headers" );
129     }
130     
131     if ( m_threadData.length() ) {
132
133         KURL url = m_thread->datURL();
134
135         url.setProtocol( "k2ch" );
136
137         // mkdir: $(KDRDIR)/share/cache/kita/pc.2ch.net/linux/xxxx.dat
138         // ¤Î¾ì¹ç¡¢kita, pc.2ch.net, linux¤òºîÀ®
139         // TODO: 3³¬ÁؤޤǤ·¤«Âбþ¤·¤Æ¤¤¤Ê¤¤¤Î¤ò¤Ê¤ó¤È¤«¤¹¤ë¡£
140         QString cachePath = Kita::Cache::getPath( url );
141         KURL cacheDir = KURL( cachePath, "." );
142         KURL cacheDir2 = KURL( cacheDir, ".." );
143         KURL cacheDir3 = KURL( cacheDir2, ".." );
144         if ( !KIO::NetAccess::exists( cacheDir3 ) ) {
145             KIO::NetAccess::mkdir( cacheDir3 );
146         }
147         if ( !KIO::NetAccess::exists( cacheDir2 ) ) {
148             KIO::NetAccess::mkdir( cacheDir2 );
149         }
150         if ( !KIO::NetAccess::exists( cacheDir ) ) {
151             KIO::NetAccess::mkdir( cacheDir );
152         }
153
154         writeCacheData( url );
155     } else retstr = "";
156
157     if ( responseCode() != 200 && responseCode() != 206 ) retstr = QString::null;
158     emit finishLoad();
159 }
160
161 // from netaccess.cpp
162 void qt_enter_modal( QWidget* widget );
163 void qt_leave_modal( QWidget* widget );
164
165 void Access::enter_loop()
166 {
167     QWidget dummy( 0, 0, WType_Dialog | WShowModal );
168     dummy.setFocusPolicy( QWidget::NoFocus );
169     qt_enter_modal( &dummy );
170     qApp->enter_loop();
171     qt_leave_modal( &dummy );
172 }
173
174 void Access::slotReceiveThreadData( KIO::Job*, const QByteArray& data )
175 {
176     QString cstr( data );
177     /* If this is the first call at resumption, remove LF at head. */
178     if(m_firstReceive) {
179         cstr = cstr.mid(1);
180     }
181     m_firstReceive = FALSE;
182     m_threadData += cstr ;
183     emit receiveData( cstr );
184 }
185
186
187 void Access::killJob()
188 {
189     if ( m_currentJob ) m_currentJob->kill();
190 }
191
192 void Access::stopJob()
193 {
194     if ( m_currentJob ) m_currentJob->kill( FALSE ); /* emit result signal */
195 }
196
197 int Access::serverTime()
198 {
199     if(m_currentJob) m_header = m_currentJob->queryMetaData( "HTTP-Headers" );
200     // parse HTTP headers
201     QStringList headerList = QStringList::split( "\n", m_header );
202     QRegExp regexp( "Date: (...), (..) (...) (....) (..:..:..) .*" );
203     QString dateStr = headerList.grep( regexp ) [ 0 ];
204     if ( regexp.search( dateStr ) == -1 ) {
205         // invalid date format
206         return QDateTime::currentDateTime().toTime_t();
207     } else {
208         // I hate this format ;p
209         QString usLocalDateStr = regexp.cap( 1 ) + " " + regexp.cap( 3 ) + " " +
210                                  regexp.cap( 2 ) + " " + regexp.cap( 5 ) + " " +
211                                  regexp.cap( 4 );
212
213         // 1970/01/01 00:00:00 GMT
214         QDateTime zeroTime( QDate( 1970, 1, 1 ), QTime( 0, 0 ) );
215         return zeroTime.secsTo( QDateTime::fromString( usLocalDateStr ) );
216     }
217 }
218
219 int Access::responseCode()
220 {
221     if(m_currentJob) m_header = m_currentJob->queryMetaData( "HTTP-Headers" );
222     // parse HTTP headers
223     QStringList headerList = QStringList::split( "\n", m_header );
224     QRegExp regexp( "HTTP/1\\.[01] ([0-9]+) .*" );
225     QString dateStr = headerList.grep( regexp ) [ 0 ];
226     if ( regexp.search( dateStr ) == -1 ) {
227         // invalid response
228         return 0;
229     } else {
230         return regexp.cap( 1 ).toInt();
231     }
232 }
233
234 QString Access::getcache()
235 {
236     KURL url = m_thread->datURL();
237     url.setProtocol( "k2ch" );
238
239     m_orgData = getCacheData( url );
240
241     return m_orgData;
242
243 }
244
245 QString Access::get()
246 {
247     QString ret;
248     ret = getcache() + getupdate();
249
250     return ret;
251 }
252
253 bool Access::deleteLog( const Thread* thread, QWidget* parent )
254 {
255     if ( QMessageBox::warning( parent,
256                                "Kita",
257                                "Do you want to delete Log ?",
258                                QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
259             == QMessageBox::Ok ) {
260
261         KURL url = thread->datURL();
262         QString str = Kita::Cache::getPath( url );
263         KIO::NetAccess::del( str );
264
265         url.setProtocol( "k2ch" );
266         str = Kita::Cache::getPath( url );
267         return KIO::NetAccess::del( str );
268     }
269     return FALSE;
270 }
271
272 #include "access.moc"