OSDN Git Service

Remove extra spaces
[kita/kita.git] / src / libkita / datinfo.cpp
1 /***************************************************************************
2 *   Copyright (C) 2004 by Kita Developers                                 *
3 *   ikemo@users.sourceforge.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
11 #include "datinfo.h"
12
13 #include <QtCore/QDir>
14 #include <QtCore/QRegExp>
15 #include <QtCore/QStringList>
16
17 #include <klocale.h>
18
19 #include "abone.h"
20 #include "access.h"
21 #include "account.h"
22 #include "cache.h"
23 #include "datmanager.h"
24 #include "globalconfig.h"
25 #include "kita_misc.h"
26 #include "kita-utf8.h"
27 #include "parser.h"
28 #include "thread.h"
29
30 using namespace Kita;
31
32 static const int RESDAT_DEFAULTSIZE = 10;
33 static const int RESDAT_DELTA = 1000;
34
35
36 /*------------------------------------------------------*/
37 /* DatInfo stores & handles all information about *.dat */
38
39 DatInfo::DatInfo(const KUrl& url) : m_threadIndex(m_datUrl),
40     m_access (0), m_access2(0)
41 {
42     QString refstr;
43     m_datUrl = getDatUrl(url, refstr);
44     m_threadIndex = ThreadIndex(m_datUrl);
45     // get the pointer of Thread class
46     m_thread = Thread::getByUrlNew(m_datUrl);
47     if (m_thread == 0) {
48
49         // create Thread
50         m_thread = Thread::getByUrl(m_datUrl);
51         if (m_thread == 0) return ;
52
53         // read idx file
54         m_threadIndex.loadIndex(m_thread);
55     }
56
57     m_thread = Thread::getByUrl(m_datUrl);
58
59     // japanese strings
60     m_spacestr = QString::fromUtf8(KITAUTF8_ZENSPACE);
61     m_framestr1 = QString::fromUtf8(KITAUTF8_FRAME1); // |
62     m_framestr2 = QString::fromUtf8(KITAUTF8_FRAME2); // |-
63     m_framestr3 = QString::fromUtf8(KITAUTF8_FRAME3); // L
64
65     // make directory
66     Cache cache(m_datUrl);
67     QString cacheDir = cache.getDirPath();
68     if (!QDir::root().mkpath(cacheDir)) return ;
69
70     initPrivate(
71         true // load cache
72    );
73 }
74
75 DatInfo::~DatInfo()
76 {
77     initPrivate(false);
78 }
79
80
81 /* Init  */
82 /* Usually, don't call this. */ /* public */
83 void DatInfo::init()
84 {
85     return initPrivate(true);
86 }
87
88 /* Init. If loadCache = true, load data from cache. */ /* private */
89 void DatInfo::initPrivate(bool loadCache)
90 {
91     // stop & delete dat loader
92     deleteAccessJob();
93
94     // init variables
95     m_broken = false;
96     m_nowLoading = false;
97     m_lastLine.clear();
98
99     // clear ResDatVec
100     m_resDatVec.clear();
101     increaseResDatVec(RESDAT_DEFAULTSIZE);
102
103     // reset Abone
104     resetAbonePrivate();
105
106     // create dat loader
107     m_access = new Access(m_datUrl);
108
109     connect(m_access, SIGNAL(receiveData(const QStringList&)),
110              SLOT(slotReceiveData(const QStringList&)));
111     connect(m_access, SIGNAL(finishLoad()), SLOT(slotFinishLoad()));
112
113     if (!loadCache) return ;
114
115     // reset ReadNum before loading cache.
116     // ReadNum & subject are updated by Access::getcache()
117     m_thread->setReadNum(0);
118
119     // get dat from cahce
120     // slotReceiveData() is called from Access::getcache()
121     m_access->getcache();
122
123     // save up-to-date thread information
124     m_threadIndex.saveIndex(m_thread);
125 }
126
127
128 /* private */
129 void DatInfo::resetResDat(RESDAT& resdat) const
130 {
131     resdat.num = 0;
132     resdat.parsed = false;
133     resdat.broken = false;
134     resdat.anclist.clear();
135     resdat.checkAbone = false;
136     resdat.abone = false;
137     resdat.isResponsed = false;
138 }
139
140
141 /* private */
142 void DatInfo::increaseResDatVec(int delta)
143 {
144     int size = m_resDatVec.size();
145     RESDAT resdat;
146     resetResDat(resdat);
147     m_resDatVec.resize(size + delta);
148     for (int i = size; i < size + delta; i++)
149         m_resDatVec[i] = resdat;
150 }
151
152
153 /* delete dat loader */ /* private */
154 void DatInfo::deleteAccessJob()
155 {
156     if (m_access) {
157         m_access->killJob();
158         delete m_access;
159         m_access = 0;
160     }
161     if (m_access2) {
162         m_access2->killJob();
163         delete m_access2;
164         m_access2 = 0;
165     }
166 }
167
168 /* public */
169 const KUrl& DatInfo::url() const
170 {
171     return m_datUrl;
172 }
173
174
175
176 /*--------------------------------------*/
177 /* cache handling functions             */
178
179 /* Update cache  */
180
181 /* When Access received new data,
182    slotReceiveData is called.           */
183
184 /* When Access fineshed loading,
185    slotFinishLoad is called, and
186    DatInfo emits the finishLoad signal to the parent object  */ /* public */
187 bool DatInfo::updateCache(const QObject* parent)
188 {
189     if (m_access == 0)
190         return false;
191     if (m_nowLoading)
192         return false;
193
194     m_nowLoading = true;
195
196     connect(this, SIGNAL(receiveData()),
197              parent, SLOT(slotReceiveData()));
198
199     connect(this, SIGNAL(finishLoad()),
200              parent, SLOT(slotFinishLoad()));
201
202     m_access->getupdate(m_thread->readNum());
203
204     return true;
205 }
206
207
208 /* slot called when Access
209    received new data              */      /* private  slot */
210 void DatInfo::slotReceiveData(const QStringList& lineList)
211 {
212     int rescode = m_access->responseCode();
213     if (m_access2) {
214         rescode = m_access2->responseCode();
215     }
216
217     if (rescode != 200 && rescode != 206) return ;
218
219     // copy lines to buffer
220     int count = lineList.count();
221     for (int i = 0; i < count ; ++i)
222         copyOneLineToResDat(lineList[ i ]);
223
224     emit receiveData();
225 }
226
227
228 /* copy one line to resdat.
229    See also DatInfo::slotReceiveData()   */ /* private */
230 bool DatInfo::copyOneLineToResDat(const QString& line)
231 {
232     if (line.isEmpty()) return false;
233
234     // update ReadNum
235     const int num = m_thread->readNum() + 1;
236     m_thread->setReadNum(num);
237
238     // If resdat vector is short, then resize the vector.
239     while ((int) m_resDatVec.size() <= num)
240         increaseResDatVec(RESDAT_DELTA);
241
242     // reset ResDat
243     RESDAT& resdat = m_resDatVec[ num ];
244     resetResDat(resdat);
245
246     resdat.num = num;
247     resdat.linestr = line;
248
249     // get subject
250     if (num == 1) parseDat(num);
251
252     // search all responses which are responsed by this line.
253     if (GlobalConfig::checkResponsed()) {
254
255         if (parseDat(num) && !checkAbonePrivate(num)) { // parse line here to get AncList
256
257             const int maxRange = 10;
258
259             AncList& anclist = m_resDatVec[ num ].anclist;
260             for (AncList::iterator it = anclist.begin(); it != anclist.end(); ++it) {
261
262                 int fromNum = (*it).from;
263                 int toNum = qMin(num - 1, (*it).to);
264                 if (toNum - fromNum + 1 > maxRange) continue;
265
266                 for (int i = fromNum; i <= toNum; ++i) {
267
268                     if (!checkAbonePrivate(i)) m_resDatVec[ i ].isResponsed = true;
269                 }
270             }
271         }
272     }
273
274     return true;
275 }
276
277
278 /* slot called when Access
279    finished loading new dat */      /* private  slot */
280 void DatInfo::slotFinishLoad()
281 {
282     // save thread information
283     m_threadIndex.saveIndex(m_thread);
284
285     // re-try by offlaw.cgi
286     DatManager datManager(m_datUrl);
287     if (m_thread->readNum() == 0 && m_access2 == 0
288             && datManager.is2chThread()) {
289         if (Account::isLogged()) {
290             initPrivate(true);
291             m_access2 = new OfflawAccess(m_datUrl);
292             connect(m_access2, SIGNAL(receiveData(const QStringList&)),
293                      SLOT(slotReceiveData(const QStringList&)));
294             connect(m_access2, SIGNAL(finishLoad()), SLOT(slotFinishLoad()));
295             m_access2->get();
296             return ;
297         }
298     }
299     // finish loading session & emit signal to the parent object
300     m_nowLoading = false;
301     emit finishLoad();
302
303     // disconnect signals
304     disconnect(SIGNAL(receiveData()));
305     disconnect(SIGNAL(finishLoad()));
306 }
307
308
309 /* public */
310 int DatInfo::getResponseCode() const
311 {
312     return (m_access == 0) ? 0 : m_access->responseCode();
313 }
314
315
316 /* public */
317 int DatInfo::getServerTime() const
318 {
319     return (m_access == 0) ? 0 : m_access->serverTime();
320 }
321
322
323 /* public */
324 bool DatInfo::deleteCache()
325 {
326     if (m_nowLoading)
327         return false;
328
329     initPrivate(false);
330
331     return true;
332 }
333
334
335 /* public */
336 bool DatInfo::isLoadingNow() const
337 {
338     return m_nowLoading;
339 }
340
341
342
343 /* public */
344 void DatInfo::stopLoading() const
345 {
346
347     // Don't lock the mutex here !!!
348     // It will cause deadlock , because
349     // Access::stopJob() calls HTMLPart::slotFinishLoad() back,
350     // then HTMLPart::slotFinishLoad() calls another functions in DatInfo.
351     if (m_access == 0)
352         return;
353     if (!m_nowLoading)
354         return;
355
356     m_access->stopJob();
357 }
358
359 /*------------------------------------------------------*/
360 /* get subject, linedata,  id, body, name, HTML, etc.   */
361
362 /* They are public */
363
364 QString DatInfo::getDat(int num)
365 {
366     return (!parseDat(num)) ? QString() : m_resDatVec[ num ].linestr;
367 }
368
369 QString DatInfo::getId(int num)
370 {
371     return (!parseDat(num)) ? QString() : m_resDatVec[ num ].id;
372 }
373
374 /* plain strings of name */
375 QString DatInfo::getPlainName(int num)
376 {
377     return (!parseDat(num)) ? QString() : m_resDatVec[ num ].name;
378 }
379
380
381 /* plain strings of title */
382 QString DatInfo::getPlainTitle(int num)
383 {
384     if (!parseDat(num)) return QString();
385
386     QString titleHtml;
387     createTitleHtml(m_resDatVec[ num ], titleHtml);
388
389     QString retStr;
390     Parser::datToText(titleHtml, retStr);
391
392     return retStr;
393 }
394
395
396 /* plain strings of body  */
397 QString DatInfo::getPlainBody(int num)
398 {
399     if (!parseDat(num)) return QString();
400
401     QString retStr;
402     Parser::datToText(m_resDatVec[ num ].bodyHTML, retStr);
403
404     return retStr;
405 }
406
407
408 /*-----------------------------------------*/
409 /* HTML data                               */
410
411
412 /* get HTML strings of title & body.
413  
414    return values are defined in datinfo.h.  */ /* public */
415
416 int DatInfo::getHTML(int num, bool checkAbone, QString& titleHTML,
417         QString& bodyHTML)
418 {
419     return getHTMLPrivate(num, checkAbone, titleHTML, bodyHTML);
420 }
421
422 /**
423  * @param[in] num
424  * @param[in] checkAbone
425  *
426  * @param[out] titleHTML
427  * @param[out] bodyHTML
428  *
429  * @retval HTML_NOTPARSED The dat is not parsed.
430  * @retval HTML_ABONE The res dat is marked as abone.
431  * @retval HTML_BROKEN The res dat is marked as broken.
432  * @retval HTML_NORMAL The res dat is normal.
433  *
434  */
435 int DatInfo::getHTMLPrivate(int num, bool checkAbone, QString& titleHtml,
436         QString& bodyHtml)
437 {
438     if (!parseDat(num)) return HTML_NOTPARSED;
439
440     bool abone = checkAbone & checkAbonePrivate(num);
441     RESDAT& resdat = m_resDatVec[ num ];
442
443     if (abone) {
444         titleHtml = QString::number(num) + ' ' + i18n("Abone");
445         bodyHtml = "<a href=\"#abone" + QString::number(num) + "\">";
446         bodyHtml += i18n("Abone") + "</a>";
447
448         return HTML_ABONE;
449     } else if (resdat.broken) {
450         titleHtml = QString::number(num) + ' ' + i18n("Broken");
451         bodyHtml = i18n("Broken");
452
453         return HTML_BROKEN;
454     } else {
455         createTitleHtml(resdat, titleHtml);
456         bodyHtml = resdat.bodyHTML;
457         
458         return HTML_NORMAL;
459     }
460 }
461
462 /* get HTML strings from startnum to endnum.
463  
464    return value is HTML strings               */  /* public */
465 QString DatInfo::getHTMLString(int startnum, int endnum, bool checkAbone)
466 {
467     QString retHTML;
468
469     for (int num = startnum; num <= endnum; num++) {
470
471         QString html;
472         getHtmlOfOneRes(num, checkAbone, html);
473         retHTML += html;
474     }
475
476     return retHTML;
477 }
478
479
480 /* return HTML strings that have ID = strid. */ /* public */
481 QString DatInfo::getHtmlById(const QString& strid, int &count)
482 {
483     QString retHTML;
484     count = 0;
485
486     for (int i = 1; i <= m_thread->readNum(); i++) {
487
488         if (!parseDat(i)) continue;
489
490         if (m_resDatVec[ i ].id == strid) {
491             count ++;
492
493             QString html;
494             getHtmlOfOneRes(i, true, html);
495             retHTML += html;
496         }
497     }
498
499     return retHTML;
500 }
501
502 /**
503  *
504  * convert res dat to html.
505  *
506  * @param[in] num
507  * @param[in] checkAbone
508  *
509  * @param[out] html
510  *
511  */
512 void DatInfo::getHtmlOfOneRes(int num, bool checkAbone, QString& html)
513 {
514     html.clear();
515     QString titleHTML, bodyHTML;
516     if (getHTMLPrivate(num, checkAbone, titleHTML, bodyHTML) == HTML_NOTPARSED)
517         return;
518
519     if (m_resDatVec[ num ].isResponsed)
520         titleHTML.replace(
521                 "<a href=\"#write", "<a class=\"coloredLink\" href=\"#write");
522     html += "<div class=\"pop_res_title\">" + titleHTML + "</div>";
523     html += "<div class=\"pop_res_body\">" + bodyHTML + "</div>";
524 }
525
526
527
528 /*-------------------------------*/
529 /* Get HTML document of res tree.*/
530 /* For example, when rootnum = 1,
531  
532 >>1 
533 |-->>4
534 |  |--->>10
535 |
536 |-->>20, and return count = 3.  */
537
538 /* Note that this function checks Abone internally. */ /* public */
539 QString DatInfo::getTreeByRes(int rootnum, int& count)
540 {
541     return getTreeByResPrivate(rootnum, false, count);
542 }
543
544 /*---------------------------------------*/
545 /* Get HTML document of reverse res tree.*/
546 /* For example, when rootnum = 10,
547  
548 >>10 
549 |-->>5
550 |  |--->>2
551 |
552 |-->>6, and returns count = 3.  */
553
554 /* Note that this function checks Abone internally. */ /* public */
555 QString DatInfo::getTreeByResReverse(int rootnum, int& count)
556 {
557     return getTreeByResPrivate(rootnum, true, count);
558 }
559
560
561 /* private */
562 QString DatInfo::getTreeByResPrivate(int rootnum,
563     bool reverse /* reverse search */, int& count)
564 {
565
566     QString tmp = QString::number(rootnum);
567     QString retstr = "<a href=\"#" + tmp + "\">&gt;&gt;" + tmp + "</a><br>";
568
569     retstr += getTreeByResCore(rootnum, reverse, count, "");
570
571     return retstr;
572 }
573
574 /* private */
575 QString DatInfo::getTreeByResCore(int rootnum,
576         bool reverse /* reverse search */, int& count, const QString& prestr)
577 {
578     if (!parseDat(rootnum))
579         return QString();
580     if (checkAbonePrivate(rootnum))
581         return QString();
582
583     QString retstr;
584     count = 0;
585     QStringList strlists;
586
587     if (!reverse) {
588
589         // collect responses that have anchor to rootnum
590         for (int i = rootnum + 1; i <= m_thread->readNum(); i++) {
591             if (checkAbonePrivate(i)) continue;
592             if (checkRes(i, rootnum)) {
593                 count ++;
594                 strlists += QString::number(i);
595             }
596         }
597
598     } else { // collect responses for which rootnum has anchors
599
600         AncList& anclist = m_resDatVec[ rootnum ].anclist;
601         for (AncList::iterator it = anclist.begin(); it != anclist.end(); ++it) {
602             for (int i = (*it).from; i <= qMin(rootnum - 1, (*it).to) ; i++) {
603                 if (checkAbonePrivate(i)) continue;
604                 count ++;
605                 strlists += QString::number(i);
606             }
607         }
608     }
609
610     // make HTML document
611     if (count) {
612
613         for (QStringList::iterator it = strlists.begin(); it != strlists.end(); ++it) {
614             QString tmpstr;
615             if ((*it) == strlists.last()) tmpstr = m_framestr3;  // 'L'
616             else tmpstr = m_framestr2;  // '|-'
617
618             retstr += prestr + tmpstr + "<a href=\"#" + (*it) + "\">&gt;&gt;" + (*it) + "</a><br>";
619
620             // call myself recursively
621             int tmpnum;
622             tmpstr = prestr;
623             if ((*it) == strlists.last()) tmpstr += m_spacestr + m_spacestr + m_spacestr; // "   "
624             else tmpstr += m_framestr1 + m_spacestr; // "| "
625             retstr += getTreeByResCore((*it).toInt(), reverse, tmpnum, tmpstr);
626             count += tmpnum;
627         }
628     }
629
630     return retstr;
631 }
632
633
634
635 /*----------------------------------------------*/
636 /* Check if No.num has anchors to No.target     */
637 /* For exsample, if target = 4, and No.num have
638    an anchor >>4, or >>2-6, etc.,
639    then return true.                            */  /* private */
640 bool DatInfo::checkRes(int num, int target)
641 {
642     const int range = 20;
643     if (!parseDat(num))
644         return false;
645
646     AncList& anclist = m_resDatVec[ num ].anclist;
647
648     for (AncList::iterator it = anclist.begin(); it != anclist.end(); ++it) {
649         if ((*it).to - (*it).from > range)
650             continue;
651         if (target >= (*it).from && target <= (*it).to)
652             return true;
653     }
654
655     return false;
656
657 }
658
659
660 /*-----------------------*/
661 /* several information */
662
663 int DatInfo::getResNum() const
664 {
665     return m_thread->resNum();
666 }
667
668 /* public */
669 int DatInfo::getReadNum() const
670 {
671     return m_thread->readNum();
672 }
673
674 /* public */
675 int DatInfo::getViewPos() const
676 {
677     return m_thread->viewPos();
678 }
679
680
681 /* return number of responses that have ID = strid. */
682 /* Note that this function checks Abone internally. */ /* public */
683 int DatInfo::getNumById(const QString& strid)
684 {
685     int count = 0;
686
687     for (int i = 1; i <= m_thread->readNum(); i++) {
688
689         if (!parseDat(i))
690             continue;
691         if (checkAbonePrivate(i))
692             continue;
693
694         if (m_resDatVec[ i ].id == strid)
695             count++;
696     }
697
698     return count;
699 }
700
701
702 /* public */
703 int DatInfo::getDatSize() const
704 {
705     return (m_access == 0) ? 0 : m_access->dataSize();
706 }
707
708
709 /* public */
710 bool DatInfo::isResponsed(int num) const
711 {
712     return m_resDatVec[ num ].isResponsed;
713 }
714
715
716 /* public */
717 bool DatInfo::isResValid(int num)
718 {
719     return parseDat(num);
720 }
721
722 /* public */
723 bool DatInfo::isBroken() const
724 {
725     if (m_broken)
726         return m_broken;
727
728     if (m_access == 0)
729         return false;
730
731     int rescode = m_access->responseCode();
732     bool invalid = m_access->invalidDataReceived();
733
734     // see also Access::slotReceiveThreadData()
735     if (invalid && (rescode == 200 || rescode == 206)) return true;
736
737     // maybe "Dat Ochi"
738     return false;
739 }
740
741 /* public */
742 bool DatInfo::isResBroken(int num)
743 {
744     return (!parseDat(num)) ? false : m_resDatVec[ num ].broken;
745 }
746
747 /* ID = strid ? */ /* public */
748 bool DatInfo::checkId(const QString& strid, int num)
749 {
750     if (!parseDat(num))
751         return false;
752
753     if (m_resDatVec[ num ].id == strid)
754         return true;
755
756     return false;
757 }
758
759
760 /* Are keywords included? */ /* public */
761 bool DatInfo::checkWord(const QStringList& stlist,   /* list of keywords */
762         int num, bool checkOr /* AND or OR search */)
763 {
764     if (!parseDat(num))
765         return false;
766
767     QString str_text = m_resDatVec[ num ].bodyHTML;
768
769     for (QStringList::const_iterator it = stlist.begin(); it != stlist.end(); ++it) {
770
771         QRegExp regexp((*it));
772         regexp.setCaseSensitivity(Qt::CaseInsensitive);
773
774         if (checkOr) { // OR
775             if (str_text.indexOf(regexp, 0) != -1) {
776                 return true;
777             }
778         } else { // AND
779             if (str_text.indexOf(regexp, 0) == -1) return false;
780         }
781     }
782
783     if (checkOr) return false;
784
785     return true;
786 }
787
788
789
790 /*--------------------------------*/
791 /* abone functions                */
792
793
794 /*-----------------------*/
795 /* reset abone.          */
796
797 /* call this when config
798    of abone changed.     */  /* public */
799
800 void DatInfo::resetAbone()
801 {
802     return resetAbonePrivate();
803 }
804
805 /* private */
806 void DatInfo::resetAbonePrivate()
807 {
808     for (int i = 1; i < (int) m_resDatVec.size(); i++)
809         m_resDatVec[ i ].checkAbone = false;
810
811     m_aboneByID = (!AboneConfig::aboneIDList().isEmpty());
812     m_aboneByName = (!AboneConfig::aboneNameList().isEmpty());
813     m_aboneByBody = (!AboneConfig::aboneWordList().isEmpty());
814     m_aboneChain = (m_aboneByID | m_aboneByName | m_aboneByBody)
815         & GlobalConfig::aboneChain() ;
816 }
817
818
819 /*--------------*/
820 /* check abone  */ /* public */
821
822 bool DatInfo::checkAbone(int num)
823 {
824     return checkAbonePrivate(num);
825 }
826
827
828 /* private */
829 bool DatInfo::checkAbonePrivate(int num)
830 {
831     if (!parseDat(num))
832         return false;
833
834     if (m_resDatVec[num].checkAbone)
835         return m_resDatVec[num].abone;
836
837     m_resDatVec[num].checkAbone = true;
838     bool checktmp = false;
839
840     if (m_aboneByID)
841         checktmp = checkAboneCore(m_resDatVec[num].id,
842                 AboneConfig::aboneIDList());
843
844     if (!checktmp && m_aboneByName)
845         checktmp = checkAboneCore(m_resDatVec[num].name,
846                 AboneConfig::aboneNameList());
847
848     if (!checktmp && m_aboneByBody)
849         checktmp = checkAboneCore(m_resDatVec[num].bodyHTML,
850                 AboneConfig::aboneWordList());
851
852     if (!checktmp && m_aboneChain) {
853         AncList & anclist = m_resDatVec[num].anclist;
854
855         for (AncList::iterator it = anclist.begin();
856                 it != anclist.end() && !checktmp ; ++it) {
857
858             int refNum = (*it).from;
859             int refNum2 = (*it).to;
860
861             // I don't want to enter loop...
862             if (refNum >= num) continue;
863             if (refNum2 >= num) refNum2 = num - 1;
864
865             for (int i = refNum; i <= refNum2; i++) {
866                 if (checkAbonePrivate(i)) {
867                     checktmp = true;
868                     break;
869                 }
870             }
871         }
872     }
873
874     m_resDatVec[num].abone = checktmp;
875
876     return m_resDatVec[num].abone;
877 }
878
879 /* private */
880 bool DatInfo::checkAboneCore(const QString& str, const QStringList& strlist)
881 const
882 {
883     if (strlist.count()) {
884
885         int i;
886         for (QStringList::const_iterator it = strlist.begin();
887                 it != strlist.end(); ++it) {
888             i = str.indexOf((*it));
889             if (i != -1) {
890                 return true;
891             }
892         }
893     }
894
895     return false;
896 }
897
898
899
900 /* parsing function for ResDat */
901 /* This function parses the raw data by parseResDat() */ /* private */
902 bool DatInfo::parseDat(int num)
903 {
904     if (num <= 0 || m_thread->readNum() < num)
905         return false;
906     if (m_resDatVec[ num ].parsed)
907         return true;
908
909     //   qDebug("parseDat %d",num);
910
911     QString subject;
912     Parser::parseResDat(m_resDatVec[ num ], subject);
913     if (num == 1 && !subject.isEmpty())
914         m_thread->setThreadName(subject);
915     if (m_resDatVec[ num ].broken)
916         m_broken = true;
917
918     return true;
919 }
920
921 bool DatInfo::isOpened() const
922 {
923     return m_isOpened;
924 }
925
926 void DatInfo::setOpened(bool isOpened)
927 {
928     m_isOpened = isOpened;
929 }
930
931 /* create HTML of title.
932   
933   struct RESDAT resdat should be parsed by parseResDat before  calling this function.
934  
935   output: titleHtml
936   
937 */
938 void DatInfo::createTitleHtml(RESDAT& resdat, QString& titleHtml)
939 {
940     titleHtml.clear();
941     if (!resdat.parsed) return ;
942
943     bool showMailAddress = GlobalConfig::showMailAddress();
944     bool useTableTag = GlobalConfig::useStyleSheet();
945
946     if (useTableTag) titleHtml += "<table class=\"res_title\"><tr>";
947
948     // res number
949     if (useTableTag) titleHtml += "<td class=\"res_title_number\">";
950     titleHtml += "<a href=\"#write" + QString::number(resdat.num) + "\">";
951     titleHtml += QString::number(resdat.num);
952     titleHtml += "</a> ";
953
954     // name & mail address
955     if (useTableTag) titleHtml += "<td class=\"res_title_name\">";
956     titleHtml += "<b>" + QString::fromUtf8(KITAUTF8_NAME);
957
958     // show name with mail address
959     if (showMailAddress) {
960
961         titleHtml += resdat.nameHTML;
962         if (!resdat.address.isEmpty()) titleHtml += " [" + resdat.address + ']';
963
964     } else { // don't show mail address
965
966         if (resdat.address.isEmpty()) {
967
968             titleHtml += "<span class=\"name_noaddr\">";
969             titleHtml += resdat.name;
970             titleHtml += "</span>";
971
972         } else {
973
974             titleHtml += "<a href=\"mailto:" + resdat.address + "\"";
975             titleHtml += " title=\"" + resdat.address + "\">";
976             titleHtml += resdat.name;
977             titleHtml += "</a>";
978         }
979     }
980
981     titleHtml += "</b> ";
982
983     // date
984     if (useTableTag) titleHtml += "<td class=\"res_title_date\">";
985     titleHtml += QString::fromUtf8(KITAUTF8_COLON) + resdat.date;
986     if (useTableTag) titleHtml += "</td>";
987
988     // ID
989     if (!resdat.id.isEmpty()) {
990
991         if (useTableTag) titleHtml += "<td class=\"res_title_id\">";
992         if (resdat.id.count("???") >= 1) titleHtml += " ID:" + resdat.id;
993         else titleHtml += " <a href=\"#idpop" + resdat.id + "\">ID</a>" + ":" + resdat.id;
994         if (useTableTag) titleHtml += "</td>";
995     }
996
997     // BE
998     if (!resdat.be.isEmpty()) {
999
1000         if (useTableTag) titleHtml += "<td class=\"res_title_be\">";
1001         titleHtml += " <a href=\"#bepop" + resdat.be + "\">?" + resdat.bepointmark + "</a>";
1002         if (useTableTag) titleHtml += "</td>";
1003     }
1004
1005     // host
1006     if (!resdat.host.isEmpty()) {
1007
1008         if (useTableTag) titleHtml += "<td class=\"res_title_host\">";
1009         titleHtml += " HOST:" + resdat.host;
1010         if (useTableTag) titleHtml += "</td>";
1011     }
1012
1013     if (useTableTag) titleHtml += "</tr></table>";
1014 }