// getpop.cpp
//
// Gets e-mail from the server and stores it in a mbox file.
//
#include <string>
#include <iostream>
#include <sstream>
#include <winsock>
#include <stdio.h>
using namespace std;
//=== Error procedure ===//
void Error (int ErrorNumber) {
switch (ErrorNumber) {
case -1:
cerr << "Unexpected error sending data." << endl; break;
case -2:
cerr << "Unexpected error getting data." << endl; break;
case 1:
cerr << "Couldn't strat winsock." << endl; break;
case 2:
cerr << "Winsock version not supported." << endl; break;
case 3:
cerr << "Couldn't resolve hostname." << endl; break;
case 4:
cerr << "Couldn't create socket." << endl; break;
case 5:
cerr << "Couldn't connect socket." << endl; break;
case 6:
cerr << "Error connecting to server." << endl; break;
case 7:
cerr << "Error sending username." << endl; break;
case 8:
cerr << "Error sending password." << endl; break;
case 9:
cerr << "Error getting number of mails." << endl; break;
case 10:
cerr << "Error asking for message." << endl; break;
case 11:
cerr << "Error deleting message." << endl; break;
case 12:
cerr << "Error quitting from server." << endl; break;
}
cerr << "Error: " << WSAGetLastError() << endl;
exit(1);
};
//=== Get connected socket ===//
SOCKET Connect (string PopServer) {
SOCKET Socket;
IN_ADDR iaHost;
LPHOSTENT lpHostEntry;
LPSERVENT lpServEnt;
SOCKADDR_IN saServer;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
// Start winsock
int nRet = WSAStartup(wVersionRequested, &wsaData);
if (nRet)
Error(1);
// Check version
if (wsaData.wVersion != wVersionRequested)
Error(2);
// resolve hostname
iaHost.s_addr = inet_addr(PopServer.c_str());
if (iaHost.s_addr == INADDR_NONE)
lpHostEntry = gethostbyname(PopServer.c_str());
else
lpHostEntry = gethostbyaddr((const char *)&iaHost, sizeof(struct in_addr), AF_INET);
if (lpHostEntry == NULL)
Error(3);
// Create socket
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Socket == INVALID_SOCKET)
Error(4);
// set port
lpServEnt = getservbyname("pop3", "tcp");
if (lpServEnt == NULL)
saServer.sin_port = htons(110);
else
saServer.sin_port = lpServEnt->s_port;
// fill the rest of the server address structure
saServer.sin_family = AF_INET;
saServer.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
// connect socket
nRet = connect(Socket, (LPSOCKADDR)&saServer, sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR) {
closesocket(Socket);
Error(5);
}
return Socket;
};
//=== Send data ===//
bool SendData (SOCKET Socket, string data) {
data += "\15\12"; // 13+10
int nRet = send(Socket, data.c_str(), data.length(), 0);
if (nRet == SOCKET_ERROR)
return false;
else
return true;
};
//=== Recieve data ===//
bool RecieveData (SOCKET Socket, string *data) {
int nRet;
string Buffer = "";
char szBuffer[1024];
for (int i=0;i<1024;i++)
szBuffer[i] = '\0';
for (;;) {
nRet = recv(Socket, szBuffer, sizeof(szBuffer), 0);
if (nRet == SOCKET_ERROR)
return false;
Buffer += szBuffer;
/* if (Buffer.find("\n") != string::npos)
break; */
/* if (Buffer != "")
break; */
if (nRet != 0)
break;
}
*data = Buffer;
return true;
};
//=== Get number of messages ===//
int NumberMessages (SOCKET Socket, string UserName, string Passwd) {
string data;
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (6);
if (!SendData (Socket, "USER " + UserName)) Error(-2);
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (7);
if (!SendData (Socket, "PASS " + Passwd)) Error(-2);
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (8);
if (!SendData (Socket, "STAT")) Error(-2);
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (9);
data.erase(0, data.find(" ")+1);
data.erase(data.find(" ")+1, data.length() - data.find(" "));
return atoi(data.c_str());
};
//=== Save message ===//
void SaveMessage (string Filename, string Buffer, long size) {
unsigned int i = 0;
string Buffer2;
string Buffer3 = "";
double c = 0;
// Adds mbox header
Buffer2 = "From ???@??? Thu Feb 13 14:52:52 2003\n";
// Jumps +OK response from server
while (!(Buffer.at(i)==13 && Buffer.at(i+1)==10)) i++;
i+=2;
cout << "Processing 0k of " << size << "k..." << endl;
// Rebuilds broken ENTERs from C++ (FIXME)
for ( ; i<Buffer.length(); i++) {
c++;
if (c/131072 == (long)c/131072)
cout << "Processing " << c/1024 << "k of " << size << "k..." << endl;
if (!(Buffer.at(i)==13 && Buffer.at(i+1)==10)) {
if (Buffer.at(i)!=1) { // FIXME - why does it throw 0x01 chars in the file???
Buffer3 += Buffer.at(i);
}
} else {
if (Buffer3 != ".") {
// Transform ".." in "."
if (Buffer3 == "..")
Buffer3 = ".";
// Add ">" before any "From" (mbox demand)
if (Buffer3.substr(0,4) == "From ")
Buffer3 = ">" + Buffer3;
Buffer2 = Buffer2 + Buffer3 + "\n";
Buffer3 = "";
i += 1;
} else
break;
}
}
cout << "Completed." << endl;
Buffer = Buffer2;
// Appends message in the file (FIXME: use streams)
const char *buf = Buffer.c_str();
FILE *f = fopen (Filename.c_str(), "a");
fprintf(f, "%s", buf);
fclose (f);
}
//=== Delete message ===//
void DeleteMessage (SOCKET Socket, int Message) {
string ss;
stringstream s;
string data;
s << Message;
s >> ss;
if (!SendData (Socket, "DELE " + ss)) Error(-2);
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (11);
}
//=== Download messages ===//
void DownloadMessages (SOCKET Socket, int Messages, string Filename, bool Del) {
string data;
string Buffer;
stringstream s;
string ss;
unsigned int len;
int TotalMessages = Messages;
if (TotalMessages == 0) {
cout << "No messages on the server." << endl;
return;
}
while (Messages != 0) {
cout << "Recieving message " << (TotalMessages-Messages+1) << " of " << TotalMessages << endl;
Buffer.erase();
s.clear();
s << (TotalMessages-Messages+1);
s >> ss;
double c = 0;
if(!SendData(Socket, "RETR " + ss)) Error (-1);
while (1) {
cout << ".";
c++;
if (c/64 == (long)c/64)
cout << " " << (int)c << "k" << endl;
data.erase();
RecieveData(Socket, &data);
Buffer += data;
len = Buffer.length();
if (len >= 4) {
if (Buffer.at(len-5) == 13
&& Buffer.at(len-4) == 10
&& Buffer.at(len-3) == 46
&& Buffer.at(len-2) == 13
&& Buffer.at(len-1) == 10)
break;
}
}
cout << " " << (long)c << "k - completed" << endl;
SaveMessage (Filename, Buffer, (long)c);
if (Del)
DeleteMessage (Socket, (TotalMessages-Messages+1));
Messages--;
}
};
//=== Quit connection ===//
void QuitConnection (SOCKET Socket) {
string data;
if (!SendData (Socket, "QUIT")) Error(-2);
if (!RecieveData (Socket, &data)) Error(-1);
if (data.at(0) != '+') Error (12);
}
//=== Close connection ===//
void CloseConnection(SOCKET Socket) {
closesocket(Socket);
};
//=== Main procedure ===//
int main(int argc, char **argv) {
SOCKET Socket;
string PopServer;
string UserName;
string Passwd;
string Filename;
string temp;
bool Del;
int Messages;
// check args
if (argc < 4 || argc > 6) {
cout << "Usage: getpop pop3.server.com username pass*d [filename] [-d]" << endl;
exit(1);
}
PopServer = argv[1];
UserName = argv[2];
Passwd = argv[3];
Del = false;
if (argc >= 5)
Filename = argv[4];
if (Filename == "-d" && argc == 5) {
Filename = "inbox.mbx";
Del = true;
}
if (argc == 6) {
temp = argv[5];
if (temp == "-d")
Del = true;
else {
cout << "Usage: getpop pop3.server.com username pass*d [filename] [-d]" << endl;
exit(1);
}
}
// Get connected socket
Socket = Connect(PopServer);
// Get number of messages
Messages = NumberMessages(Socket, UserName, Passwd);
// Download messages
DownloadMessages(Socket, Messages, Filename, Del);
// Close connection
CloseConnection(Socket);
return 0;
}