Small library for reading mail messages via POP3. Currently doesn\'t return all header fields, and does only plain text authorization.

Dependents:   mmain pop3demo

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