Small library for reading mail messages via POP3. Currently doesn\'t return all header fields, and does only plain text authorization.
pop3.cpp
- Committer:
- hlipka
- Date:
- 2011-01-10
- Revision:
- 0:ec8a3cef200d
- Child:
- 1:f2b05d1c91be
File content as of revision 0:ec8a3cef200d:
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; }