1//
2// POP3ClientSession.cpp
3//
4// Library: Net
5// Package: Mail
6// Module: POP3ClientSession
7//
8// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/POP3ClientSession.h"
16#include "Poco/Net/MailMessage.h"
17#include "Poco/Net/MailStream.h"
18#include "Poco/Net/SocketAddress.h"
19#include "Poco/Net/NetException.h"
20#include "Poco/StreamCopier.h"
21#include "Poco/NumberFormatter.h"
22#include "Poco/UnbufferedStreamBuf.h"
23#include "Poco/Ascii.h"
24#include <istream>
25
26
27using Poco::NumberFormatter;
28using Poco::StreamCopier;
29
30
31namespace Poco {
32namespace Net {
33
34
35class DialogStreamBuf: public Poco::UnbufferedStreamBuf
36{
37public:
38 DialogStreamBuf(DialogSocket& socket):
39 _socket(socket)
40 {
41 }
42
43 ~DialogStreamBuf()
44 {
45 }
46
47private:
48 int readFromDevice()
49 {
50 return _socket.get();
51 }
52
53 DialogSocket& _socket;
54};
55
56
57class DialogIOS: public virtual std::ios
58{
59public:
60 DialogIOS(DialogSocket& socket):
61 _buf(socket)
62 {
63 poco_ios_init(&_buf);
64 }
65
66 ~DialogIOS()
67 {
68 }
69
70 DialogStreamBuf* rdbuf()
71 {
72 return &_buf;
73 }
74
75protected:
76 DialogStreamBuf _buf;
77};
78
79
80class DialogInputStream: public DialogIOS, public std::istream
81{
82public:
83 DialogInputStream(DialogSocket& socket):
84 DialogIOS(socket),
85 std::istream(&_buf)
86 {
87 }
88
89 ~DialogInputStream()
90 {
91 }
92};
93
94
95POP3ClientSession::POP3ClientSession(const StreamSocket& socket):
96 _socket(socket),
97 _isOpen(true)
98{
99}
100
101
102POP3ClientSession::POP3ClientSession(const std::string& host, Poco::UInt16 port):
103 _socket(SocketAddress(host, port)),
104 _isOpen(true)
105{
106}
107
108
109POP3ClientSession::~POP3ClientSession()
110{
111 try
112 {
113 close();
114 }
115 catch (...)
116 {
117 }
118}
119
120
121void POP3ClientSession::setTimeout(const Poco::Timespan& timeout)
122{
123 _socket.setReceiveTimeout(timeout);
124}
125
126
127Poco::Timespan POP3ClientSession::getTimeout() const
128{
129 return _socket.getReceiveTimeout();
130}
131
132
133void POP3ClientSession::login(const std::string& username, const std::string& password)
134{
135 std::string response;
136 _socket.receiveMessage(response);
137 if (!isPositive(response)) throw POP3Exception("The POP3 service is unavailable", response);
138 sendCommand("USER", username, response);
139 if (!isPositive(response)) throw POP3Exception("Login rejected for user", response);
140 sendCommand("PASS", password, response);
141 if (!isPositive(response)) throw POP3Exception("Password rejected for user", response);
142}
143
144
145void POP3ClientSession::close()
146{
147 if (_isOpen)
148 {
149 std::string response;
150 sendCommand("QUIT", response);
151 _socket.close();
152 _isOpen = false;
153 }
154}
155
156
157int POP3ClientSession::messageCount()
158{
159 std::string response;
160 sendCommand("STAT", response);
161 if (!isPositive(response)) throw POP3Exception("Cannot determine message count", response);
162 std::string::const_iterator it = response.begin();
163 std::string::const_iterator end = response.end();
164 int count = 0;
165 while (it != end && !Poco::Ascii::isSpace(*it)) ++it;
166 while (it != end && Poco::Ascii::isSpace(*it)) ++it;
167 while (it != end && Poco::Ascii::isDigit(*it)) count = count*10 + *it++ - '0';
168 return count;
169}
170
171
172void POP3ClientSession::listMessages(MessageInfoVec& messages)
173{
174 messages.clear();
175 std::string response;
176 sendCommand("LIST", response);
177 if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
178 _socket.receiveMessage(response);
179 while (response != ".")
180 {
181 MessageInfo info = {0, 0};
182 std::string::const_iterator it = response.begin();
183 std::string::const_iterator end = response.end();
184 while (it != end && Poco::Ascii::isDigit(*it)) info.id = info.id*10 + *it++ - '0';
185 while (it != end && Poco::Ascii::isSpace(*it)) ++it;
186 while (it != end && Poco::Ascii::isDigit(*it)) info.size = info.size*10 + *it++ - '0';
187 messages.push_back(info);
188 _socket.receiveMessage(response);
189 }
190}
191
192
193void POP3ClientSession::retrieveMessage(int id, MailMessage& message)
194{
195 std::string response;
196 sendCommand("RETR", NumberFormatter::format(id), response);
197 if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
198 DialogInputStream sis(_socket);
199 MailInputStream mis(sis);
200 message.read(mis);
201 while (mis.good()) mis.get(); // read any remaining junk
202}
203
204
205void POP3ClientSession::retrieveMessage(int id, MailMessage& message, PartHandler& handler)
206{
207 std::string response;
208 sendCommand("RETR", NumberFormatter::format(id), response);
209 if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
210 DialogInputStream sis(_socket);
211 MailInputStream mis(sis);
212 message.read(mis, handler);
213 while (mis.good()) mis.get(); // read any remaining junk
214}
215
216
217void POP3ClientSession::retrieveMessage(int id, std::ostream& ostr)
218{
219 std::string response;
220 sendCommand("RETR", NumberFormatter::format(id), response);
221 if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
222 DialogInputStream sis(_socket);
223 MailInputStream mis(sis);
224 StreamCopier::copyStream(mis, ostr);
225}
226
227
228void POP3ClientSession::retrieveHeader(int id, MessageHeader& header)
229{
230 std::string response;
231 sendCommand("TOP", NumberFormatter::format(id), "0", response);
232 if (!isPositive(response)) throw POP3Exception("Cannot retrieve header", response);
233 DialogInputStream sis(_socket);
234 MailInputStream mis(sis);
235 MessageHeader::RecipientList recipients;
236 header.read(mis, &recipients);
237 // skip stuff following header
238 mis.get(); // \r
239 mis.get(); // \n
240}
241
242
243void POP3ClientSession::deleteMessage(int id)
244{
245 std::string response;
246 sendCommand("DELE", NumberFormatter::format(id), response);
247 if (!isPositive(response)) throw POP3Exception("Cannot mark message for deletion", response);
248}
249
250
251bool POP3ClientSession::sendCommand(const std::string& command, std::string& response)
252{
253 _socket.sendMessage(command);
254 _socket.receiveMessage(response);
255 return isPositive(response);
256}
257
258
259bool POP3ClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
260{
261 _socket.sendMessage(command, arg);
262 _socket.receiveMessage(response);
263 return isPositive(response);
264}
265
266
267bool POP3ClientSession::sendCommand(const std::string& command, const std::string& arg1, const std::string& arg2, std::string& response)
268{
269 _socket.sendMessage(command, arg1, arg2);
270 _socket.receiveMessage(response);
271 return isPositive(response);
272}
273
274
275bool POP3ClientSession::isPositive(const std::string& response)
276{
277 return response.length() > 0 && response[0] == '+';
278}
279
280
281} } // namespace Poco::Net
282