1 /*
2 ** Copyright 2003, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #include "nntpxpat.H"
7 #include <sstream>
8 
9 using namespace std;
10 
XpatTaskCallback(mail::searchCallback * cb)11 mail::nntp::XpatTaskCallback::XpatTaskCallback(mail::searchCallback *cb)
12 	: realCallback(cb)
13 {
14 }
15 
~XpatTaskCallback()16 mail::nntp::XpatTaskCallback::~XpatTaskCallback()
17 {
18 }
19 
success(std::string message)20 void mail::nntp::XpatTaskCallback::success(std::string message)
21 {
22 	// Should NOT happen
23 
24 	fail(message);
25 }
26 
fail(std::string message)27 void mail::nntp::XpatTaskCallback::fail(std::string message)
28 {
29 	mail::searchCallback *cb=realCallback;
30 
31 	realCallback=NULL;
32 
33 	delete this;
34 
35 	cb->fail(message);
36 }
37 
reportProgress(size_t bytesCompleted,size_t bytesEstimatedTotal,size_t messagesCompleted,size_t messagesEstimatedTotal)38 void mail::nntp::XpatTaskCallback::reportProgress(size_t bytesCompleted,
39 						  size_t bytesEstimatedTotal,
40 
41 						  size_t messagesCompleted,
42 						  size_t messagesEstimatedTotal
43 						  )
44 {
45 	realCallback->reportProgress(bytesCompleted, bytesEstimatedTotal,
46 				     messagesCompleted,
47 				     messagesEstimatedTotal);
48 }
49 
50 
XpatTask(XpatTaskCallback * cbArg,nntp & serverArg,string groupName,string hdrArg,string srchArg,bool searchNotArg,searchParams::Scope searchScopeArg,size_t rangeLoArg,size_t rangeHiArg)51 mail::nntp::XpatTask::XpatTask(XpatTaskCallback *cbArg,
52 			       nntp &serverArg, string groupName,
53 			       string hdrArg,
54 			       string srchArg, bool searchNotArg,
55 			       searchParams::Scope searchScopeArg,
56 			       size_t rangeLoArg, size_t rangeHiArg)
57 	: GroupTask(cbArg, serverArg, groupName),
58 	  cb(cbArg),
59 	  hdr(hdrArg),
60 	  srch(srchArg),
61 	  searchNot(searchNotArg),
62 	  searchScope(searchScopeArg),
63 	  rangeLo(rangeLoArg),
64 	  rangeHi(rangeHiArg)
65 {
66 }
67 
~XpatTask()68 mail::nntp::XpatTask::~XpatTask()
69 {
70 	if (cb)
71 		delete cb;
72 }
73 
selectedGroup(msgnum_t estimatedCount,msgnum_t loArticleCount,msgnum_t hiArticleCount)74 void mail::nntp::XpatTask::selectedGroup(msgnum_t estimatedCount,
75 			   msgnum_t loArticleCount,
76 			   msgnum_t hiArticleCount)
77 {
78 	response_func= &mail::nntp::XpatTask::processStatusResponse;
79 
80 	vector<mail::nntp::nntpMessageInfo>::iterator b, e;
81 
82 	b=myserver->index.begin();
83 	e=myserver->index.end();
84 
85 	while (b != e)
86 	{
87 		b->msgFlag &= ~IDX_SEARCH;
88 
89 		++b;
90 	}
91 
92 	lastIdxMsgNum=myserver->index.begin();
93 	ostringstream o;
94 
95 	o << "XPAT " << hdr << " " <<
96 		(myserver->index.size() > 0 ?
97 		 myserver->index[0].msgNum:1) << "- *" << srch << "*\r\n";
98 
99 	myserver->socketWrite(o.str());
100 
101 }
102 
processGroup(const char * line)103 void mail::nntp::XpatTask::processGroup(const char *line)
104 {
105 	(this->*response_func)(line);
106 }
107 
processStatusResponse(const char * line)108 void mail::nntp::XpatTask::processStatusResponse(const char *line)
109 {
110 	if (line[0] != '2')
111 	{
112 		done(line);
113 		return;
114 	}
115 	response_func= &mail::nntp::XpatTask::processXpatResponse;
116 }
117 
processXpatResponse(const char * l)118 void mail::nntp::XpatTask::processXpatResponse(const char *l)
119 {
120 	if (*l == '.')
121 		done("OK");
122 
123 	msgnum_t n;
124 
125 	istringstream i(l);
126 
127 	i >> n;
128 
129 	if (i.fail() || myserver->index.size() == 0)
130 		return;
131 
132 	if (lastIdxMsgNum == myserver->index.end())
133 		--lastIdxMsgNum;
134 
135 	for (;;)
136 	{
137 		if (lastIdxMsgNum->msgNum > n)
138 		{
139 			if (lastIdxMsgNum == myserver->index.begin())
140 				break;
141 			--lastIdxMsgNum;
142 			if (lastIdxMsgNum->msgNum < n)
143 				break;
144 			continue;
145 		}
146 		else if (lastIdxMsgNum->msgNum < n)
147 		{
148 			if (++lastIdxMsgNum == myserver->index.end())
149 				break;
150 			if (lastIdxMsgNum->msgNum > n)
151 				break;
152 		}
153 		else
154 		{
155 			myserver->index[lastIdxMsgNum
156 					- myserver->index.begin()].msgFlag
157 				|= IDX_SEARCH;
158 			break;
159 		}
160 	}
161 }
162 
done(const char * l)163 void mail::nntp::XpatTask::done(const char *l)
164 {
165 	unsigned char Xor=0;
166 	unsigned char Ror=0;
167 
168 	if (searchNot)
169 		Xor=IDX_SEARCH;
170 
171 	switch (searchScope) {
172 	case searchParams::search_all:
173 		Ror=IDX_SEARCH;
174 		break;
175 
176 	case searchParams::search_unmarked:
177 		Xor |= IDX_FLAGGED;
178 		break;
179 
180 	case searchParams::search_marked:
181 		break;
182 
183 	case searchParams::search_range:
184 		Ror=IDX_FLAGGED;
185 		break;
186 	}
187 
188 	vector<size_t> searchResults;
189 
190 	vector<nntpMessageInfo>::iterator bb,b, e;
191 
192 	bb=b=myserver->index.begin();
193 	e=myserver->index.end();
194 
195 	if (searchScope == searchParams::search_range)
196 	{
197 		if (rangeHi > myserver->index.size())
198 			rangeHi=myserver->index.size();
199 
200 		if (rangeLo > rangeHi)
201 			rangeLo=rangeHi;
202 
203 		e= b + rangeHi;
204 		b += rangeLo;
205 	}
206 
207 	while (b != e)
208 	{
209 		unsigned char f= (b->msgFlag ^ Xor) | Ror;
210 
211 		if ((f & IDX_FLAGGED) && (f & IDX_SEARCH))
212 			searchResults.push_back(b - bb);
213 
214 		++b;
215 
216 	}
217 
218 	searchCallback *cbPat=cb->realCallback;
219 
220 	delete cb;
221 	cb=NULL;
222 	callbackPtr=NULL;
223 
224 	try {
225 		Task::done();
226 	} catch (...) {
227 		cbPat->success(searchResults);
228 		throw;
229 	}
230 	cbPat->success(searchResults);
231 }
232