Small library for reading mail messages via POP3. Currently doesn\'t return all header fields, and does only plain text authorization.
Diff: pop3.cpp
- Revision:
- 0:ec8a3cef200d
- Child:
- 1:f2b05d1c91be
diff -r 000000000000 -r ec8a3cef200d pop3.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pop3.cpp Mon Jan 10 21:11:01 2011 +0000 @@ -0,0 +1,320 @@ +p#include "pop3.h" +#include "dnsresolve.h" + +class Pop3CommandResponse +{ + public: + Pop3CommandResponse(string line); + bool addLine(string line); + + bool success; + string responseLine; + list<string> responseLines; +}; + +Pop3::Pop3(const char* servername, const char* username, const char* password) { + _username=username; + _password=password; + _servername=servername; + + _readpos=0; + _readlen=0; + + _closed=false; + + _socket.setOnEvent(this,&Pop3::onTCPSocketEvent); +} + +Pop3::~Pop3() { + close(); +} + +void Pop3::onTCPSocketEvent(TCPSocketEvent e) { +// printf("New TCPSocketEvent: %d\n",e); + switch (e) { + case TCPSOCKET_CONNECTED: + _connected = true; + _connecting=false; + break; + + case TCPSOCKET_READABLE: + break; + case TCPSOCKET_WRITEABLE: + break; + + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + case TCPSOCKET_DISCONNECTED: { + _socket.close(); + _connected = false; + _connecting=false; + } + break; + } +} + +list<string> *Pop3::getMessages() { + Pop3CommandResponse* pcr=sendCommandMultiResponse("LIST"); + if (!pcr->success) { + delete pcr; + return NULL; + } + list<string> *ids=new list<string>(); + list<string> lines=pcr->responseLines; + list<string>::iterator it; + for ( it=lines.begin() ; it != lines.end(); it++ ) { + string line=*it; + string id=line.substr(0,line.find(' ')); + ids->push_back(id); + } + delete pcr; + return ids; +} + +Pop3Message* Pop3::getMessage(string id, bool getSig, bool deleteOnReceive) { + Pop3CommandResponse* pcr=sendCommandMultiResponse(string("RETR ").append(id)); + if (!pcr->success) { + delete pcr; + return NULL; + } + Pop3Message *msg=new Pop3Message(); + list<string> lines=pcr->responseLines; + list<string>::iterator it; + for ( it=lines.begin() ; it != lines.end(); it++ ) { + string line=*it; + if (0==line.find("From: ")) { + msg->from=line.substr(6); + } else if (0==line.find("Subject: ")) { + msg->subject=line.substr(9); + } else if (0==line.length()) { + break; + } + } + for (/* use iterator from above - it start right at the content */ ; it != lines.end(); it++ ) { + string line=*it; + if (!getSig && 0==line.compare("-- ")) + break; + msg->content.push_back(line); + } + delete pcr; + if (deleteOnReceive) + { + pcr=deleteMessage(id); + delete pcr; + } + return msg; +} + +bool Pop3::deleteMessage(string id) { + Pop3CommandResponse* pcr=sendCommandMultiResponse(string("DELE ").append(id)); + if (!pcr->success) { + delete pcr; + return false; + } + delete pcr; + return true; +} + + +Pop3CommandResponse* Pop3::sendCommand(string cmd) { +// printf("send [%s]\n",cmd.c_str()); + if (!_connected) { + printf("not connected\n"); + return NULL; + } + int err=_socket.send(cmd.append("\r\n").c_str(),cmd.length()+2); + Net::poll(); + string r=readResponseLine(); + return new Pop3CommandResponse(r); +} + +Pop3CommandResponse* Pop3::sendCommandMultiResponse(string cmd) { + // first, send command +// printf("send [%s]\n",cmd.c_str()); + if (!_connected) { + printf("not connected\n"); + return NULL; + } + int err=_socket.send(cmd.append("\r\n").c_str(),cmd.length()+2); + Net::poll(); + // read first response line -> contains status + string r=readResponseLine(); +// printf("response=[%s]\n",r.c_str()); + // create response object to collect remaining lines + Pop3CommandResponse *pcr=new Pop3CommandResponse(r); + if (!pcr->success) + return pcr; + // read other lines, stop when marker reached + while (true) { + r=readResponseLine(); + if (pcr->addLine(r)) + break; + } + return pcr; +} + +bool Pop3::init() { + // retrieve IP address for hostname + DNSResolver *dnsr=new DNSResolver(); + IpAddr addr=dnsr->resolveName(_servername); + delete dnsr; + + if (addr.isNull()) { + printf("cannot resolve server name %s\n",_servername); + return false; + } + +// printf("server ip=%i.%i.%i.%i\n",addr[0],addr[1],addr[2],addr[3]); + + _connecting=true; + + // create tcp socket to server + Host host(addr, 110); + + TCPSocketErr bindErr = _socket.connect(host); + + if (bindErr != 0) { + printf("connection error %i\n", bindErr); + return false; + } + + // wait for connection established + Timer tmr; + tmr.start(); + + while (_connecting) { + Net::poll(); + wait(0.1); + if (tmr.read()>10) + break; + } + + if (!_connected) { + printf("error - could not connect (timeout)\n"); + return false; + } + + // read server banner + string banner=readResponseLine(); +// printf("banner=[%s]\n",banner.c_str()); + + Pop3CommandResponse pcr(banner); + if (!pcr.success) + return false; + + // send username + string cmd=string("user ").append(_username); + Pop3CommandResponse *response=sendCommand(cmd); + + if (!response->success) { + delete response; + return false; + } + + delete response; + + // send password + cmd=string("pass ").append(_password); + response=sendCommand(cmd); + + if (!response->success) { + delete response; + return false; + } + + delete response; + + return true; +} + +void Pop3::close() { + if (_closed) + return; + + Pop3CommandResponse *pcr=sendCommand("CLOSE"); + delete pcr; + + while (_connected) { + Net::poll(); + // read remaining data + int err=_socket.recv(_readbuf,BUFSIZE-1); + if (err<=0) + break; + } + + _socket.resetOnEvent(); + _socket.close(); + + _closed=true; +} + +string Pop3::readResponseLine() { + string r; + bool got_r=false; + + if (!_connected) + return r; + + while (true) { + Net::poll(); + if (_readlen>_readpos) { + while (_readbuf[_readpos]!=0 && _readpos<_readlen) { + char c=_readbuf[_readpos++]; + if (!got_r) { + if (c=='\r') { + got_r=true; + } else { + r.push_back(c); + } + } else { + if (c=='\n') { + return r; + } else { + r.push_back('\r'); // push missed \r also, so push it to string + r.push_back(c); + got_r=false; + } + } + } + } else { + int err=_socket.recv(_readbuf,BUFSIZE-1); + if (err < 0) { + printf("error while receiving data: %i!\n",err); + } else if (err>0) { + _readbuf[err]=0; + _readlen=err; + _readpos=0; + } + } + wait(0.1); + if (_connected==false) { + return r; + } + } +} + +Pop3CommandResponse::Pop3CommandResponse(string line) { + if (0==line.find("+OK")) { + success=true; + responseLine=line.substr(4); + } else if (0==line.find("-ERR")) { + success=false; + responseLine=line.substr(5); + } else { + success=false; + } + +} + +bool Pop3CommandResponse::addLine(string line) { + // last line is single dot only + if (line.length()==1 && line.at(0)=='.') + return true; + // remove leading dot if any + if (line.length()>0 && line.at(0)=='.') + line=line.substr(1); + responseLines.push_back(line); + return false; +} \ No newline at end of file