1 /*
2 ** Copyright 2003, Double Precision Inc.
3 **
4 ** See COPYING for distribution information.
5 */
6 #include "nntpfetch.H"
7 #include <sstream>
8 
9 using namespace std;
10 
FetchTaskBase(mail::callback * callbackArg,nntp & myserverArg,std::string groupNameArg,size_t msgNumArg,std::string uidArg,mail::readMode getTypeArg)11 mail::nntp::FetchTaskBase::FetchTaskBase(mail::callback *callbackArg,
12 					 nntp &myserverArg,
13 					 std::string groupNameArg,
14 					 size_t msgNumArg,
15 					 std::string uidArg,
16 					 mail::readMode getTypeArg)
17 	: GroupTask(callbackArg, myserverArg, groupNameArg),
18 	  msgNum(msgNumArg),
19 	  uid(uidArg),
20 	  getType(getTypeArg)
21 {
22 }
23 
~FetchTaskBase()24 mail::nntp::FetchTaskBase::~FetchTaskBase()
25 {
26 }
27 
selectedGroup(msgnum_t estimatedCount,msgnum_t loArticleCount,msgnum_t hiArticleCount)28 void mail::nntp::FetchTaskBase::selectedGroup(msgnum_t estimatedCount,
29 					  msgnum_t loArticleCount,
30 					  msgnum_t hiArticleCount)
31 {
32 	response_func= &mail::nntp::FetchTaskBase::processStatusResponse;
33 
34 	if (!myserver->fixGenericMessageNumber(uid, msgNum))
35 	{
36 		fail("Invalid message number.");
37 		return;
38 	}
39 
40 	byteCount=0;
41 	ostringstream o;
42 
43 	switch (getType) {
44 	case mail::readContents:
45 		o << "BODY ";
46 		break;
47 	case mail::readBoth:
48 		o << "ARTICLE ";
49 		break;
50 	default:
51 		o << "HEAD ";
52 	}
53 
54 	o << myserver->index[msgNum].msgNum << "\r\n";
55 
56 	myserver->socketWrite(o.str());
57 }
58 
processGroup(const char * cmd)59 void mail::nntp::FetchTaskBase::processGroup(const char *cmd)
60 {
61 	(this->*response_func)(cmd);
62 }
63 
processStatusResponse(const char * msg)64 void mail::nntp::FetchTaskBase::processStatusResponse(const char *msg)
65 {
66 	if (msg[0] != '2')
67 	{
68 		ostringstream o;
69 
70 		o << "The following error occured while reading this article:\n"
71 			"\n"
72 			"    " << msg << "\n\n";
73 
74 		fetchedText(o.str());
75 		success("Ok");
76 		return;
77 	}
78 
79 	response_func= getType == mail::readHeadersFolded
80 		? &mail::nntp::FetchTaskBase::processFetchFoldedResponse:
81 		&mail::nntp::FetchTaskBase::processFetchResponse;
82 	foldedNewline=false;
83 }
84 
processFetchResponse(const char * cmd)85 void mail::nntp::FetchTaskBase::processFetchResponse(const char *cmd)
86 {
87 	if (strcmp(cmd, "."))
88 	{
89 		if (*cmd == '.')
90 			++cmd;
91 
92 		string s(cmd);
93 
94 		s += "\n";
95 
96 		byteCount += s.size();
97 		if (callbackPtr)
98 			callbackPtr->reportProgress(byteCount, 0, 0, 1);
99 		fetchedText(s);
100 		return;
101 	}
102 
103 	if (callbackPtr)
104 		callbackPtr->reportProgress(byteCount, byteCount, 0, 1);
105 	success("Ok\n");
106 }
107 
processFetchFoldedResponse(const char * cmd)108 void mail::nntp::FetchTaskBase::processFetchFoldedResponse(const char *cmd)
109 {
110 	if (strcmp(cmd, "."))
111 	{
112 		if (*cmd == '.')
113 			++cmd;
114 
115 		if (*cmd && unicode_isspace((unsigned char)*cmd) &&
116 		    foldedNewline)
117 		{
118 			while (*cmd && unicode_isspace((unsigned char)*cmd))
119 				cmd++;
120 
121 			string s(" ");
122 			s += cmd;
123 
124 			byteCount += s.size();
125 
126 			if (callbackPtr)
127 				callbackPtr->
128 					reportProgress(byteCount, 0, 0, 1);
129 			fetchedText(s);
130 		}
131 		else
132 		{
133 			string s;
134 
135 			if (foldedNewline)
136 				s += "\n";
137 			foldedNewline=true;
138 			s += cmd;
139 
140 			byteCount += s.size();
141 			if (callbackPtr)
142 				callbackPtr->
143 					reportProgress(byteCount, 0, 0, 1);
144 			fetchedText(s);
145 		}
146 		return;
147 	}
148 	++byteCount;
149 
150 	if (callbackPtr)
151 		callbackPtr->reportProgress(byteCount, byteCount, 0, 1);
152 
153 	fetchedText("\n");
154 	success("Ok");
155 }
156 
157 //
158 // TaskBase is recyled by CacheTask, which also fetches a message's contents,
159 // but does not have a callback::message, because it goes into a temporary
160 // file.  That's why we separate out callback::message-specific processing
161 // into a subclass.
162 //
163 
FetchTask(callback::message * textCallbackArg,nntp & myserverArg,std::string groupNameArg,size_t msgNumArg,std::string uidArg,mail::readMode getType)164 mail::nntp::FetchTask::FetchTask(callback::message *textCallbackArg,
165 				 nntp &myserverArg,
166 				 std::string groupNameArg,
167 				 size_t msgNumArg,
168 				 std::string uidArg,
169 				 mail::readMode getType)
170 	: FetchTaskBase(textCallbackArg, myserverArg,
171 			groupNameArg,
172 			msgNumArg,
173 			uidArg,
174 			getType),
175 	  textCallback(*textCallbackArg)
176 {
177 }
178 
~FetchTask()179 mail::nntp::FetchTask::~FetchTask()
180 {
181 }
182 
fetchedText(std::string s)183 void mail::nntp::FetchTask::fetchedText(std::string s)
184 {
185 	textCallback.messageTextCallback(msgNum, s);
186 }
187