mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
258 lines
5.3 KiB
C++
258 lines
5.3 KiB
C++
#include "POP3.h"
|
|
|
|
namespace Upp {
|
|
|
|
static bool sPop3Trace;
|
|
#define LLOG(x) do { if(sPop3Trace) RLOG(CompressLog(String().Cat() << x)); } while(0)
|
|
|
|
void Pop3::Trace(bool b)
|
|
{
|
|
sPop3Trace = b;
|
|
}
|
|
|
|
Pop3& Pop3::Proxy(const char *p)
|
|
{
|
|
proxy_port = 8080;
|
|
ParseProxyUrl(p, proxy_host, proxy_port);
|
|
return *this;
|
|
}
|
|
|
|
String Pop3::GetTimeStamp()
|
|
{
|
|
int begin = data.Find('<');
|
|
if(begin >= 0) {
|
|
int end = data.Find('>', begin);
|
|
if(end > begin) {
|
|
end++;
|
|
return data.Mid(begin, end - begin);
|
|
}
|
|
}
|
|
return Null;
|
|
}
|
|
|
|
bool Pop3::GetListItems(ValueMap& list, dword type1, dword type2)
|
|
{
|
|
StringStream s(data);
|
|
while(!s.IsEof()) {
|
|
String line = s.GetLine();
|
|
Vector<String> s = Split(line, ' ');
|
|
if(s.GetCount() < 2)
|
|
return false;
|
|
list.Add(Scan(type1, s[0]), Scan(type2, s[1]));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int Pop3::GetMessageCount()
|
|
{
|
|
if(!PutGet("STAT\r\n"))
|
|
return Null;
|
|
String ok, cnt, tsz;
|
|
if(!SplitTo(data, ' ', ok, cnt, tsz))
|
|
return Null;
|
|
return StrInt(cnt);
|
|
}
|
|
|
|
String Pop3::GetMessage(int index)
|
|
{
|
|
if(!PutGet(Format("RETR %d\r\n", index), true))
|
|
return Null;
|
|
return data;
|
|
}
|
|
|
|
String Pop3::GetMessageHeader(int index)
|
|
{
|
|
if(!PutGet(Format("TOP %d %d\r\n", index, 0), true))
|
|
return Null;
|
|
return data;
|
|
}
|
|
|
|
bool Pop3::GetMessageList(ValueMap& list)
|
|
{
|
|
if(!PutGet("LIST\r\n", true))
|
|
return false;
|
|
return GetListItems(list, INT_V, INT_V);
|
|
}
|
|
|
|
|
|
String Pop3::GetMessageUniqueId(int index)
|
|
{
|
|
if(!PutGet(Format("UIDL %d\r\n", index)))
|
|
return Null;
|
|
String ok, id, tsz;
|
|
if(!SplitTo(data, ' ', ok, id, tsz))
|
|
return Null;
|
|
return id;
|
|
}
|
|
|
|
bool Pop3::GetMessageUniqueIds(ValueMap& uids)
|
|
{
|
|
if(!PutGet("UIDL\r\n", true))
|
|
return false;
|
|
return GetListItems(uids, INT_V, STRING_V);
|
|
}
|
|
|
|
bool Pop3::RemoveMessage(int index)
|
|
{
|
|
return PutGet(Format("DELE %d\r\n", index));
|
|
}
|
|
|
|
bool Pop3::Undo()
|
|
{
|
|
return PutGet("RSET\r\n");
|
|
}
|
|
|
|
bool Pop3::Noop()
|
|
{
|
|
return PutGet("NOOP\r\n");
|
|
}
|
|
|
|
bool Pop3::PutGet(const String& s, bool multiline, bool nolog)
|
|
{
|
|
// Put() request.
|
|
if(!s.IsEmpty()) {
|
|
if(!nolog)
|
|
LLOG(">> " << TrimRight(s));
|
|
if(!PutAll(s)) {
|
|
LLOG("-- " << GetLastError());
|
|
return false;
|
|
}
|
|
}
|
|
// Get() respone.
|
|
data.Clear();
|
|
const int MAXLINE = 20000000;
|
|
String line = GetLine(MAXLINE);
|
|
if(!line.IsVoid()) {
|
|
LLOG("<< " << TrimRight(line));
|
|
if(line.StartsWith("+OK")) {
|
|
if(!multiline) {
|
|
data.Cat(line);
|
|
data.Cat("\r\n");
|
|
return true;
|
|
}
|
|
else
|
|
for(;;) {
|
|
line = GetLine(MAXLINE);
|
|
if(line.IsVoid())
|
|
break;
|
|
if(line == ".") {
|
|
LLOG("<< ...");
|
|
return true;
|
|
}
|
|
data.Cat(*line == '.' ? line.Mid(1) : line);
|
|
data.Cat("\r\n");
|
|
}
|
|
}
|
|
else
|
|
if(line.StartsWith("-ERR"))
|
|
error = line;
|
|
}
|
|
LLOG("-- " << GetLastError());
|
|
return false;
|
|
}
|
|
|
|
bool Pop3::Authenticate()
|
|
{
|
|
// Try using APOP authentication.
|
|
String timestamp = GetTimeStamp();
|
|
if(!timestamp.IsEmpty()) {
|
|
if(PutGet("APOP " + user + " " + MD5String(timestamp << pass) + "\r\n"))
|
|
return true;
|
|
}
|
|
else
|
|
if(PutGet("USER " + user + "\r\n")) {
|
|
LLOG(">>PASS ******");
|
|
if(PutGet("PASS " + pass + "\r\n", false, true))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Pop3::Login()
|
|
{
|
|
try {
|
|
if(host.IsEmpty())
|
|
throw Exc(t_("Hostname is not specified."));
|
|
if(user.IsEmpty())
|
|
throw Exc(t_("Username is not specified."));
|
|
if(pass.IsEmpty())
|
|
throw Exc(t_("Password is nor specified."));
|
|
if(proxy_host.GetCount()) {
|
|
String host_port = host;
|
|
host_port << ':' << Nvl(port, ssl ? 995 : 110);
|
|
String data;
|
|
data << "CONNECT " << host_port << " HTTP/1.1\r\n"
|
|
<< "Host: " << host_port << "\r\n";
|
|
if(!IsNull(proxy_username))
|
|
data << "Proxy-Authorization: Basic "
|
|
<< Base64Encode(proxy_username + ':' + proxy_password) << "\r\n";
|
|
data << "\r\n";
|
|
LLOG("Trying to connect proxy " << proxy_host << ":" << proxy_port);
|
|
if(!Connect(proxy_host, proxy_port))
|
|
throw Exc("Unable to connect the proxy");
|
|
LLOG("About to send proxy request:\n" << data);
|
|
if(!PutAll(data))
|
|
throw Exc("Unable to send request to the proxy");
|
|
String response;
|
|
for(;;) {
|
|
String l = GetLine();
|
|
if(l.GetCount() == 0)
|
|
break;
|
|
LLOG("< " << l);
|
|
if(response.GetCount() == 0)
|
|
response = l;
|
|
}
|
|
LLOG("Proxy response: " << response);
|
|
if(!response.StartsWith("HTTP") || response.Find(" 2") < 0)
|
|
throw Exc("Invalid proxy reply: " + response);
|
|
LLOG("Connected via proxy");
|
|
}
|
|
else
|
|
if(!Connect(host, Nvl(port, ssl ? 995 : 110)))
|
|
throw Exc(GetErrorDesc());
|
|
LLOG(Format(t_("Opening connection to %s:%d."), host, port));
|
|
if(ssl) {
|
|
if(!StartSSL())
|
|
throw Exc(t_("Couldn't start SSL session."));
|
|
LLOG(t_("SSL session successfully started."));
|
|
}
|
|
// Receive server greetings.
|
|
if(!PutGet(Null))
|
|
throw Exc(GetLastError());
|
|
if(!Authenticate())
|
|
throw Exc(GetLastError());
|
|
}
|
|
catch (Exc e) {
|
|
error = e;
|
|
LLOG("-- " + e);
|
|
Logout();
|
|
return false;
|
|
}
|
|
return online = true;
|
|
}
|
|
|
|
bool Pop3::Logout()
|
|
{
|
|
if(IsOnline())
|
|
PutGet("QUIT\r\n");
|
|
LLOG(Format(t_("Closing connection to %s:%d."), host, port));
|
|
if(IsOpen())
|
|
Close();
|
|
online = false;
|
|
return true;
|
|
}
|
|
|
|
Pop3::Pop3()
|
|
{
|
|
ssl = false;
|
|
online = false;
|
|
Timeout(60000);
|
|
}
|
|
|
|
Pop3::~Pop3()
|
|
{
|
|
Logout();
|
|
}
|
|
|
|
}
|