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

Dependents:   mmain pop3demo

Committer:
hlipka
Date:
Mon Jan 10 21:11:01 2011 +0000
Revision:
0:ec8a3cef200d
Child:
1:f2b05d1c91be
initial version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hlipka 0:ec8a3cef200d 1 p#include "pop3.h"
hlipka 0:ec8a3cef200d 2 #include "dnsresolve.h"
hlipka 0:ec8a3cef200d 3
hlipka 0:ec8a3cef200d 4 class Pop3CommandResponse
hlipka 0:ec8a3cef200d 5 {
hlipka 0:ec8a3cef200d 6 public:
hlipka 0:ec8a3cef200d 7 Pop3CommandResponse(string line);
hlipka 0:ec8a3cef200d 8 bool addLine(string line);
hlipka 0:ec8a3cef200d 9
hlipka 0:ec8a3cef200d 10 bool success;
hlipka 0:ec8a3cef200d 11 string responseLine;
hlipka 0:ec8a3cef200d 12 list<string> responseLines;
hlipka 0:ec8a3cef200d 13 };
hlipka 0:ec8a3cef200d 14
hlipka 0:ec8a3cef200d 15 Pop3::Pop3(const char* servername, const char* username, const char* password) {
hlipka 0:ec8a3cef200d 16 _username=username;
hlipka 0:ec8a3cef200d 17 _password=password;
hlipka 0:ec8a3cef200d 18 _servername=servername;
hlipka 0:ec8a3cef200d 19
hlipka 0:ec8a3cef200d 20 _readpos=0;
hlipka 0:ec8a3cef200d 21 _readlen=0;
hlipka 0:ec8a3cef200d 22
hlipka 0:ec8a3cef200d 23 _closed=false;
hlipka 0:ec8a3cef200d 24
hlipka 0:ec8a3cef200d 25 _socket.setOnEvent(this,&Pop3::onTCPSocketEvent);
hlipka 0:ec8a3cef200d 26 }
hlipka 0:ec8a3cef200d 27
hlipka 0:ec8a3cef200d 28 Pop3::~Pop3() {
hlipka 0:ec8a3cef200d 29 close();
hlipka 0:ec8a3cef200d 30 }
hlipka 0:ec8a3cef200d 31
hlipka 0:ec8a3cef200d 32 void Pop3::onTCPSocketEvent(TCPSocketEvent e) {
hlipka 0:ec8a3cef200d 33 // printf("New TCPSocketEvent: %d\n",e);
hlipka 0:ec8a3cef200d 34 switch (e) {
hlipka 0:ec8a3cef200d 35 case TCPSOCKET_CONNECTED:
hlipka 0:ec8a3cef200d 36 _connected = true;
hlipka 0:ec8a3cef200d 37 _connecting=false;
hlipka 0:ec8a3cef200d 38 break;
hlipka 0:ec8a3cef200d 39
hlipka 0:ec8a3cef200d 40 case TCPSOCKET_READABLE:
hlipka 0:ec8a3cef200d 41 break;
hlipka 0:ec8a3cef200d 42 case TCPSOCKET_WRITEABLE:
hlipka 0:ec8a3cef200d 43 break;
hlipka 0:ec8a3cef200d 44
hlipka 0:ec8a3cef200d 45 case TCPSOCKET_CONTIMEOUT:
hlipka 0:ec8a3cef200d 46 case TCPSOCKET_CONRST:
hlipka 0:ec8a3cef200d 47 case TCPSOCKET_CONABRT:
hlipka 0:ec8a3cef200d 48 case TCPSOCKET_ERROR:
hlipka 0:ec8a3cef200d 49 case TCPSOCKET_DISCONNECTED: {
hlipka 0:ec8a3cef200d 50 _socket.close();
hlipka 0:ec8a3cef200d 51 _connected = false;
hlipka 0:ec8a3cef200d 52 _connecting=false;
hlipka 0:ec8a3cef200d 53 }
hlipka 0:ec8a3cef200d 54 break;
hlipka 0:ec8a3cef200d 55 }
hlipka 0:ec8a3cef200d 56 }
hlipka 0:ec8a3cef200d 57
hlipka 0:ec8a3cef200d 58 list<string> *Pop3::getMessages() {
hlipka 0:ec8a3cef200d 59 Pop3CommandResponse* pcr=sendCommandMultiResponse("LIST");
hlipka 0:ec8a3cef200d 60 if (!pcr->success) {
hlipka 0:ec8a3cef200d 61 delete pcr;
hlipka 0:ec8a3cef200d 62 return NULL;
hlipka 0:ec8a3cef200d 63 }
hlipka 0:ec8a3cef200d 64 list<string> *ids=new list<string>();
hlipka 0:ec8a3cef200d 65 list<string> lines=pcr->responseLines;
hlipka 0:ec8a3cef200d 66 list<string>::iterator it;
hlipka 0:ec8a3cef200d 67 for ( it=lines.begin() ; it != lines.end(); it++ ) {
hlipka 0:ec8a3cef200d 68 string line=*it;
hlipka 0:ec8a3cef200d 69 string id=line.substr(0,line.find(' '));
hlipka 0:ec8a3cef200d 70 ids->push_back(id);
hlipka 0:ec8a3cef200d 71 }
hlipka 0:ec8a3cef200d 72 delete pcr;
hlipka 0:ec8a3cef200d 73 return ids;
hlipka 0:ec8a3cef200d 74 }
hlipka 0:ec8a3cef200d 75
hlipka 0:ec8a3cef200d 76 Pop3Message* Pop3::getMessage(string id, bool getSig, bool deleteOnReceive) {
hlipka 0:ec8a3cef200d 77 Pop3CommandResponse* pcr=sendCommandMultiResponse(string("RETR ").append(id));
hlipka 0:ec8a3cef200d 78 if (!pcr->success) {
hlipka 0:ec8a3cef200d 79 delete pcr;
hlipka 0:ec8a3cef200d 80 return NULL;
hlipka 0:ec8a3cef200d 81 }
hlipka 0:ec8a3cef200d 82 Pop3Message *msg=new Pop3Message();
hlipka 0:ec8a3cef200d 83 list<string> lines=pcr->responseLines;
hlipka 0:ec8a3cef200d 84 list<string>::iterator it;
hlipka 0:ec8a3cef200d 85 for ( it=lines.begin() ; it != lines.end(); it++ ) {
hlipka 0:ec8a3cef200d 86 string line=*it;
hlipka 0:ec8a3cef200d 87 if (0==line.find("From: ")) {
hlipka 0:ec8a3cef200d 88 msg->from=line.substr(6);
hlipka 0:ec8a3cef200d 89 } else if (0==line.find("Subject: ")) {
hlipka 0:ec8a3cef200d 90 msg->subject=line.substr(9);
hlipka 0:ec8a3cef200d 91 } else if (0==line.length()) {
hlipka 0:ec8a3cef200d 92 break;
hlipka 0:ec8a3cef200d 93 }
hlipka 0:ec8a3cef200d 94 }
hlipka 0:ec8a3cef200d 95 for (/* use iterator from above - it start right at the content */ ; it != lines.end(); it++ ) {
hlipka 0:ec8a3cef200d 96 string line=*it;
hlipka 0:ec8a3cef200d 97 if (!getSig && 0==line.compare("-- "))
hlipka 0:ec8a3cef200d 98 break;
hlipka 0:ec8a3cef200d 99 msg->content.push_back(line);
hlipka 0:ec8a3cef200d 100 }
hlipka 0:ec8a3cef200d 101 delete pcr;
hlipka 0:ec8a3cef200d 102 if (deleteOnReceive)
hlipka 0:ec8a3cef200d 103 {
hlipka 0:ec8a3cef200d 104 pcr=deleteMessage(id);
hlipka 0:ec8a3cef200d 105 delete pcr;
hlipka 0:ec8a3cef200d 106 }
hlipka 0:ec8a3cef200d 107 return msg;
hlipka 0:ec8a3cef200d 108 }
hlipka 0:ec8a3cef200d 109
hlipka 0:ec8a3cef200d 110 bool Pop3::deleteMessage(string id) {
hlipka 0:ec8a3cef200d 111 Pop3CommandResponse* pcr=sendCommandMultiResponse(string("DELE ").append(id));
hlipka 0:ec8a3cef200d 112 if (!pcr->success) {
hlipka 0:ec8a3cef200d 113 delete pcr;
hlipka 0:ec8a3cef200d 114 return false;
hlipka 0:ec8a3cef200d 115 }
hlipka 0:ec8a3cef200d 116 delete pcr;
hlipka 0:ec8a3cef200d 117 return true;
hlipka 0:ec8a3cef200d 118 }
hlipka 0:ec8a3cef200d 119
hlipka 0:ec8a3cef200d 120
hlipka 0:ec8a3cef200d 121 Pop3CommandResponse* Pop3::sendCommand(string cmd) {
hlipka 0:ec8a3cef200d 122 // printf("send [%s]\n",cmd.c_str());
hlipka 0:ec8a3cef200d 123 if (!_connected) {
hlipka 0:ec8a3cef200d 124 printf("not connected\n");
hlipka 0:ec8a3cef200d 125 return NULL;
hlipka 0:ec8a3cef200d 126 }
hlipka 0:ec8a3cef200d 127 int err=_socket.send(cmd.append("\r\n").c_str(),cmd.length()+2);
hlipka 0:ec8a3cef200d 128 Net::poll();
hlipka 0:ec8a3cef200d 129 string r=readResponseLine();
hlipka 0:ec8a3cef200d 130 return new Pop3CommandResponse(r);
hlipka 0:ec8a3cef200d 131 }
hlipka 0:ec8a3cef200d 132
hlipka 0:ec8a3cef200d 133 Pop3CommandResponse* Pop3::sendCommandMultiResponse(string cmd) {
hlipka 0:ec8a3cef200d 134 // first, send command
hlipka 0:ec8a3cef200d 135 // printf("send [%s]\n",cmd.c_str());
hlipka 0:ec8a3cef200d 136 if (!_connected) {
hlipka 0:ec8a3cef200d 137 printf("not connected\n");
hlipka 0:ec8a3cef200d 138 return NULL;
hlipka 0:ec8a3cef200d 139 }
hlipka 0:ec8a3cef200d 140 int err=_socket.send(cmd.append("\r\n").c_str(),cmd.length()+2);
hlipka 0:ec8a3cef200d 141 Net::poll();
hlipka 0:ec8a3cef200d 142 // read first response line -> contains status
hlipka 0:ec8a3cef200d 143 string r=readResponseLine();
hlipka 0:ec8a3cef200d 144 // printf("response=[%s]\n",r.c_str());
hlipka 0:ec8a3cef200d 145 // create response object to collect remaining lines
hlipka 0:ec8a3cef200d 146 Pop3CommandResponse *pcr=new Pop3CommandResponse(r);
hlipka 0:ec8a3cef200d 147 if (!pcr->success)
hlipka 0:ec8a3cef200d 148 return pcr;
hlipka 0:ec8a3cef200d 149 // read other lines, stop when marker reached
hlipka 0:ec8a3cef200d 150 while (true) {
hlipka 0:ec8a3cef200d 151 r=readResponseLine();
hlipka 0:ec8a3cef200d 152 if (pcr->addLine(r))
hlipka 0:ec8a3cef200d 153 break;
hlipka 0:ec8a3cef200d 154 }
hlipka 0:ec8a3cef200d 155 return pcr;
hlipka 0:ec8a3cef200d 156 }
hlipka 0:ec8a3cef200d 157
hlipka 0:ec8a3cef200d 158 bool Pop3::init() {
hlipka 0:ec8a3cef200d 159 // retrieve IP address for hostname
hlipka 0:ec8a3cef200d 160 DNSResolver *dnsr=new DNSResolver();
hlipka 0:ec8a3cef200d 161 IpAddr addr=dnsr->resolveName(_servername);
hlipka 0:ec8a3cef200d 162 delete dnsr;
hlipka 0:ec8a3cef200d 163
hlipka 0:ec8a3cef200d 164 if (addr.isNull()) {
hlipka 0:ec8a3cef200d 165 printf("cannot resolve server name %s\n",_servername);
hlipka 0:ec8a3cef200d 166 return false;
hlipka 0:ec8a3cef200d 167 }
hlipka 0:ec8a3cef200d 168
hlipka 0:ec8a3cef200d 169 // printf("server ip=%i.%i.%i.%i\n",addr[0],addr[1],addr[2],addr[3]);
hlipka 0:ec8a3cef200d 170
hlipka 0:ec8a3cef200d 171 _connecting=true;
hlipka 0:ec8a3cef200d 172
hlipka 0:ec8a3cef200d 173 // create tcp socket to server
hlipka 0:ec8a3cef200d 174 Host host(addr, 110);
hlipka 0:ec8a3cef200d 175
hlipka 0:ec8a3cef200d 176 TCPSocketErr bindErr = _socket.connect(host);
hlipka 0:ec8a3cef200d 177
hlipka 0:ec8a3cef200d 178 if (bindErr != 0) {
hlipka 0:ec8a3cef200d 179 printf("connection error %i\n", bindErr);
hlipka 0:ec8a3cef200d 180 return false;
hlipka 0:ec8a3cef200d 181 }
hlipka 0:ec8a3cef200d 182
hlipka 0:ec8a3cef200d 183 // wait for connection established
hlipka 0:ec8a3cef200d 184 Timer tmr;
hlipka 0:ec8a3cef200d 185 tmr.start();
hlipka 0:ec8a3cef200d 186
hlipka 0:ec8a3cef200d 187 while (_connecting) {
hlipka 0:ec8a3cef200d 188 Net::poll();
hlipka 0:ec8a3cef200d 189 wait(0.1);
hlipka 0:ec8a3cef200d 190 if (tmr.read()>10)
hlipka 0:ec8a3cef200d 191 break;
hlipka 0:ec8a3cef200d 192 }
hlipka 0:ec8a3cef200d 193
hlipka 0:ec8a3cef200d 194 if (!_connected) {
hlipka 0:ec8a3cef200d 195 printf("error - could not connect (timeout)\n");
hlipka 0:ec8a3cef200d 196 return false;
hlipka 0:ec8a3cef200d 197 }
hlipka 0:ec8a3cef200d 198
hlipka 0:ec8a3cef200d 199 // read server banner
hlipka 0:ec8a3cef200d 200 string banner=readResponseLine();
hlipka 0:ec8a3cef200d 201 // printf("banner=[%s]\n",banner.c_str());
hlipka 0:ec8a3cef200d 202
hlipka 0:ec8a3cef200d 203 Pop3CommandResponse pcr(banner);
hlipka 0:ec8a3cef200d 204 if (!pcr.success)
hlipka 0:ec8a3cef200d 205 return false;
hlipka 0:ec8a3cef200d 206
hlipka 0:ec8a3cef200d 207 // send username
hlipka 0:ec8a3cef200d 208 string cmd=string("user ").append(_username);
hlipka 0:ec8a3cef200d 209 Pop3CommandResponse *response=sendCommand(cmd);
hlipka 0:ec8a3cef200d 210
hlipka 0:ec8a3cef200d 211 if (!response->success) {
hlipka 0:ec8a3cef200d 212 delete response;
hlipka 0:ec8a3cef200d 213 return false;
hlipka 0:ec8a3cef200d 214 }
hlipka 0:ec8a3cef200d 215
hlipka 0:ec8a3cef200d 216 delete response;
hlipka 0:ec8a3cef200d 217
hlipka 0:ec8a3cef200d 218 // send password
hlipka 0:ec8a3cef200d 219 cmd=string("pass ").append(_password);
hlipka 0:ec8a3cef200d 220 response=sendCommand(cmd);
hlipka 0:ec8a3cef200d 221
hlipka 0:ec8a3cef200d 222 if (!response->success) {
hlipka 0:ec8a3cef200d 223 delete response;
hlipka 0:ec8a3cef200d 224 return false;
hlipka 0:ec8a3cef200d 225 }
hlipka 0:ec8a3cef200d 226
hlipka 0:ec8a3cef200d 227 delete response;
hlipka 0:ec8a3cef200d 228
hlipka 0:ec8a3cef200d 229 return true;
hlipka 0:ec8a3cef200d 230 }
hlipka 0:ec8a3cef200d 231
hlipka 0:ec8a3cef200d 232 void Pop3::close() {
hlipka 0:ec8a3cef200d 233 if (_closed)
hlipka 0:ec8a3cef200d 234 return;
hlipka 0:ec8a3cef200d 235
hlipka 0:ec8a3cef200d 236 Pop3CommandResponse *pcr=sendCommand("CLOSE");
hlipka 0:ec8a3cef200d 237 delete pcr;
hlipka 0:ec8a3cef200d 238
hlipka 0:ec8a3cef200d 239 while (_connected) {
hlipka 0:ec8a3cef200d 240 Net::poll();
hlipka 0:ec8a3cef200d 241 // read remaining data
hlipka 0:ec8a3cef200d 242 int err=_socket.recv(_readbuf,BUFSIZE-1);
hlipka 0:ec8a3cef200d 243 if (err<=0)
hlipka 0:ec8a3cef200d 244 break;
hlipka 0:ec8a3cef200d 245 }
hlipka 0:ec8a3cef200d 246
hlipka 0:ec8a3cef200d 247 _socket.resetOnEvent();
hlipka 0:ec8a3cef200d 248 _socket.close();
hlipka 0:ec8a3cef200d 249
hlipka 0:ec8a3cef200d 250 _closed=true;
hlipka 0:ec8a3cef200d 251 }
hlipka 0:ec8a3cef200d 252
hlipka 0:ec8a3cef200d 253 string Pop3::readResponseLine() {
hlipka 0:ec8a3cef200d 254 string r;
hlipka 0:ec8a3cef200d 255 bool got_r=false;
hlipka 0:ec8a3cef200d 256
hlipka 0:ec8a3cef200d 257 if (!_connected)
hlipka 0:ec8a3cef200d 258 return r;
hlipka 0:ec8a3cef200d 259
hlipka 0:ec8a3cef200d 260 while (true) {
hlipka 0:ec8a3cef200d 261 Net::poll();
hlipka 0:ec8a3cef200d 262 if (_readlen>_readpos) {
hlipka 0:ec8a3cef200d 263 while (_readbuf[_readpos]!=0 && _readpos<_readlen) {
hlipka 0:ec8a3cef200d 264 char c=_readbuf[_readpos++];
hlipka 0:ec8a3cef200d 265 if (!got_r) {
hlipka 0:ec8a3cef200d 266 if (c=='\r') {
hlipka 0:ec8a3cef200d 267 got_r=true;
hlipka 0:ec8a3cef200d 268 } else {
hlipka 0:ec8a3cef200d 269 r.push_back(c);
hlipka 0:ec8a3cef200d 270 }
hlipka 0:ec8a3cef200d 271 } else {
hlipka 0:ec8a3cef200d 272 if (c=='\n') {
hlipka 0:ec8a3cef200d 273 return r;
hlipka 0:ec8a3cef200d 274 } else {
hlipka 0:ec8a3cef200d 275 r.push_back('\r'); // push missed \r also, so push it to string
hlipka 0:ec8a3cef200d 276 r.push_back(c);
hlipka 0:ec8a3cef200d 277 got_r=false;
hlipka 0:ec8a3cef200d 278 }
hlipka 0:ec8a3cef200d 279 }
hlipka 0:ec8a3cef200d 280 }
hlipka 0:ec8a3cef200d 281 } else {
hlipka 0:ec8a3cef200d 282 int err=_socket.recv(_readbuf,BUFSIZE-1);
hlipka 0:ec8a3cef200d 283 if (err < 0) {
hlipka 0:ec8a3cef200d 284 printf("error while receiving data: %i!\n",err);
hlipka 0:ec8a3cef200d 285 } else if (err>0) {
hlipka 0:ec8a3cef200d 286 _readbuf[err]=0;
hlipka 0:ec8a3cef200d 287 _readlen=err;
hlipka 0:ec8a3cef200d 288 _readpos=0;
hlipka 0:ec8a3cef200d 289 }
hlipka 0:ec8a3cef200d 290 }
hlipka 0:ec8a3cef200d 291 wait(0.1);
hlipka 0:ec8a3cef200d 292 if (_connected==false) {
hlipka 0:ec8a3cef200d 293 return r;
hlipka 0:ec8a3cef200d 294 }
hlipka 0:ec8a3cef200d 295 }
hlipka 0:ec8a3cef200d 296 }
hlipka 0:ec8a3cef200d 297
hlipka 0:ec8a3cef200d 298 Pop3CommandResponse::Pop3CommandResponse(string line) {
hlipka 0:ec8a3cef200d 299 if (0==line.find("+OK")) {
hlipka 0:ec8a3cef200d 300 success=true;
hlipka 0:ec8a3cef200d 301 responseLine=line.substr(4);
hlipka 0:ec8a3cef200d 302 } else if (0==line.find("-ERR")) {
hlipka 0:ec8a3cef200d 303 success=false;
hlipka 0:ec8a3cef200d 304 responseLine=line.substr(5);
hlipka 0:ec8a3cef200d 305 } else {
hlipka 0:ec8a3cef200d 306 success=false;
hlipka 0:ec8a3cef200d 307 }
hlipka 0:ec8a3cef200d 308
hlipka 0:ec8a3cef200d 309 }
hlipka 0:ec8a3cef200d 310
hlipka 0:ec8a3cef200d 311 bool Pop3CommandResponse::addLine(string line) {
hlipka 0:ec8a3cef200d 312 // last line is single dot only
hlipka 0:ec8a3cef200d 313 if (line.length()==1 && line.at(0)=='.')
hlipka 0:ec8a3cef200d 314 return true;
hlipka 0:ec8a3cef200d 315 // remove leading dot if any
hlipka 0:ec8a3cef200d 316 if (line.length()>0 && line.at(0)=='.')
hlipka 0:ec8a3cef200d 317 line=line.substr(1);
hlipka 0:ec8a3cef200d 318 responseLines.push_back(line);
hlipka 0:ec8a3cef200d 319 return false;
hlipka 0:ec8a3cef200d 320 }