// 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; }