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:
Tue Jan 11 21:35:35 2011 +0000
Revision:
1:f2b05d1c91be
Parent:
0:ec8a3cef200d
Child:
2:3893c1aaee8d
fixed compile error & include handling

Who changed what in which revision?

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