// Windows XP FAQ Poll // // Douglas Thrift // // Poller.cpp #include "Poller.h" Poller::Poller() { string mailbox = session->list("\"\" \"" + account.getMailbox() + "\""); if (mailbox.find(account.getMailbox()) == string::npos) { cerr << program << ": Mailbox does not exist: " << account.getMailbox() << "\n"; exit(1); } } Poller::~Poller() { if (!nodelete) { session->expunge(); } } void Poller::poll(bool nodelete, const string& file) { this->nodelete = nodelete; this->file = file; load(); ballots(); approvals(); save(); } void Poller::load() { ifstream fin(file.c_str()); if (!fin.is_open()) { fin.clear(); ofstream fout(file.c_str()); fout << "_find_\n" << "reply=0\n" << "news=0\n" << "sig=0\n" << "search=0\n" << "link=0\n" << "browse=0\n" << "other=0\n" << "_help_\n" << "solved=0\n" << "note=0\n" << "link=0\n" << "news=0\n" << "lazy=0\n" << "_improve_\n" << "nothing=0\n" << "links=0\n" << "suggest=0\n"; fout.close(); fin.open(file.c_str()); } while (fin.good()) { enum { FIND, HELP, IMPROVE } type; string vote; unsigned count; string text; fin.peek() != '_' ? getline(fin, vote, '=') : getline(fin, vote); if (debug) cerr << "vote = " << vote << "\n"; if (vote == "_find_") { type = FIND; continue; } else if (vote == "_help_") { type = HELP; continue; } else if (vote == "_improve_") { type = IMPROVE; continue; } else if (vote == "approved" || vote == "approve") { getline(fin, text); } else { fin >> count; fin.get(); } if (fin.peek() == EOF) fin.get(); switch (type) { case FIND: if (vote == "reply") { find.reply = count; } else if (vote == "news") { find.news = count; } else if (vote == "sig") { find.sig = count; } else if (vote == "search") { find.search = count; } else if (vote == "link") { find.link = count; } else if (vote == "browse") { find.browse = count; } else if (vote == "other") { find.other = count; } else if (vote == "approved") { find.approved.push_back(text); } else if (vote == "approve") { find.approve.push_back(text); } break; case HELP: if (vote == "solved") { help.solved = count; } else if (vote == "note") { help.note = count; } else if (vote == "link") { help.link = count; } else if (vote == "news") { help.news = count; } else if (vote == "lazy") { help.lazy = count; } break; case IMPROVE: if (vote == "nothing") { improve.nothing = count; } else if (vote == "links") { improve.links = count; } else if (vote == "suggest") { improve.suggest = count; } else if (vote == "approved") { improve.approved.push_back(text); } else if (vote == "approve") { improve.approve.push_back(text); } break; } } fin.close(); } void Poller::save() { unsigned index; ofstream fout(file.c_str()); fout << "_find_\n" << "reply=" << find.reply << "\n" << "news=" << find.news << "\n" << "sig=" << find.sig << "\n" << "search=" << find.search << "\n" << "link=" << find.link << "\n" << "browse=" << find.browse << "\n" << "other=" << find.other << "\n"; for (index = 0; index < find.approved.size(); index++) { fout << "approved=" << find.approved[index] << "\n"; } for (index = 0; index < find.approve.size(); index++) { fout << "approve=" << find.approve[index] << "\n"; } fout << "_help_\n" << "solved=" << help.solved << "\n" << "note=" << help.note << "\n" << "link=" << help.link << "\n" << "news=" << help.news << "\n" << "lazy=" << help.lazy << "\n" << "_improve_\n" << "nothing=" << improve.nothing << "\n" << "links=" << improve.links << "\n" << "suggest=" << improve.suggest << "\n"; for (index = 0; index < improve.approved.size(); index++) { fout << "approved=" << improve.approved[index] << "\n"; } for (index = 0; index < improve.approve.size(); index++) { fout << "approve=" << improve.approve[index] << "\n"; } fout.close(); } void Poller::ballots() { session->select('\"' + account.getMailbox() + '\"'); stringstream search; search << session->search(string("ALL HEADER X-Mailer \"WinXPFAQPoll 1.0 ") + "(Perl)\" SUBJECT \"Windows XP FAQ | Poll Ballot\" FROM \"Windows XP" + " FAQ | Poll\""); search.ignore(9); search.peek(); while (search.good()) { unsigned message; search >> message; if (debug) cerr << "message = " << message << "\n"; messages.push(message); search.get(); search.peek(); } if (!messages.empty()) { unsigned message = messages.front(); messages.pop(); ballot(message); } if (submits.size() > 0) { cout << "Sending submits..." << flush; for (unsigned index = 0; index < submits.size(); index++) { submit(submits[index].first, submits[index].second); } submits.clear(); cout << "done.\n"; } } void Poller::ballot(unsigned message) { cout << "Checking message: " << message << "..." << flush; ostringstream number; number << message; stringstream buffer; buffer << session->fetch(number.str() + " BODY.PEEK[2]"); if (session->successful() && session->fetch(number.str() + " FLAGS").find( "\\Deleted") == string::npos) { buffer.ignore(string::npos, '\n'); bool approved = session->fetch(number.str() + " FLAGS").find("\\Flagge" + string("d")) != string::npos; while (buffer.peek() != '\n' && buffer.good()) { enum { FIND, HELP, IMPROVE } type; string vote; getline(buffer, vote); if (debug) cerr << "vote = " << vote << "\n"; if (vote == "_find_") { type = FIND; continue; } else if (vote == "_help_") { type = HELP; continue; } else if (vote == "_improve_") { type = IMPROVE; continue; } buffer.peek(); switch (type) { case FIND: if (vote == "reply") { find.reply++; } else if (vote == "news") { find.news++; } else if (vote == "sig") { find.sig++; } else if (vote == "search") { find.search++; } else if (vote == "link") { find.link++; } else if (vote == "browse") { find.browse++; } else if (vote == "other") { find.other++; string text; getline(buffer, text); if (approved) { find.approved.push_back(text); } else { find.approve.push_back(text); submits.push_back(pair("find", text)); } } break; case HELP: if (vote == "solved") { help.solved++; } else if (vote == "note") { help.note++; } else if (vote == "link") { help.link++; } else if (vote == "news") { help.news++; } else if (vote == "lazy") { help.lazy++; } break; case IMPROVE: if (vote == "nothing") { improve.nothing++; } else if (vote == "links") { improve.links++; } else if (vote == "suggest") { improve.suggest++; string text; getline(buffer, text); if (approved) { improve.approved.push_back(text); } else { improve.approve.push_back(text); submits.push_back(pair("improve", text)); } } break; } } session->store(number.str() + " +FLAGS (\\Deleted)"); cout << "done.\n"; } else { cout << "cancelled.\n"; } if (!messages.empty()) { unsigned message = messages.front(); messages.pop(); ballot(message); } } void Poller::submit(const string& type, const string& text) { ostringstream message; message << "From: \"Windows XP FAQ | Poll\" <" << account.getEmail() << ">\n" << "To: \"" << account.getName() << "\" <" << account.getEmail() << ">\n" << "Subject: Windows XP FAQ | Poll Submit\n" << "Content-Type: text/plain charset=\"us-ascii\"\n" << "Content-Transfer-Encoding: 7bit\n" << "X-Mailer: WinXPFAQPoll 1.0\n" << "X-WinXPFAQPoll-Submit-Type: " << type << "\n" << "X-WinXPFAQPoll-Submit-Text: " << text << "\n\n"; if (type == "find") { message << "How did you find this page?\n" << " I arrived here by entirely different means:\n"; } else if (type == "improve") { message << "How could I improve this site?\n" << " I have my own completely insane suggestion:\n"; } message << " " << text << "\n\n" << "Flag this message to approve the voter\'s possibly objectionable\n" << "input or delete it to disapprove.\n\n" << "This message will be marked deleted when it is processed.\n"; ostringstream length; length << (message.str().length() + 16); session->append('\"' + account.getMailbox() + "\" {" + length.str() + '}', message.str()); session->noop(); } void Poller::approvals() { unsigned index; session->check(); for (index = find.approve.size(); index > 0; index--) { cout << "Checking find: " << index << "..." << flush; switch (approval("find", find.approve[index - 1])) { case true: find.approved.push_back(find.approve[index - 1]); case false: find.approve.erase(find.approve.begin() + (index - 1)); break; default: break; } } for (index = improve.approve.size(); index > 0; index--) { cout << "Checking improve: " << index << "..." << flush; switch (approval("improve", improve.approve[index - 1])) { case true: improve.approved.push_back(improve.approve[index - 1]); case false: improve.approve.erase(improve.approve.begin() + (index - 1)); break; default: break; } } if (find.disapprove.size() > 0 || improve.disapprove.size() > 0) { cout << "Sending disapprovals..." << flush; ostringstream message; message << "From: \"Windows XP FAQ | Poll\" <" << account.getEmail() << ">\n" << "To: \"" << account.getName() << "\" <" << account.getEmail() << ">\n" << "Subject: Windows XP FAQ | Poll Disapprovals\n" << "Content-Type: multipart/mixed;\n" << " boundary=\"----=_NextPart_WinXPFAQPoll_0\"\n" << "Content-Transfer-Encoding: 7bit\n" << "X-Mailer: WinXPFAQPoll 1.0\n\n" << "This is a multi-part message in MIME format.\n\n" << "------=_NextPart_WinXPFAQPoll_0\n" << "Content-Type: text/plain charset=\"us-ascii\"\n" << "Content-Transfer-Encoding: 7bit\n\n" << "Apparently these answers where disapproved:\n\n"; unsigned extra = 0; for (index = 0; index < find.disapprove.size(); index++, extra += 4) { message << "How did you find this page?\n" << " I arrived here by entirely different means:\n" << " " << find.disapprove[index] << "\n\n"; } for (index = 0; index < improve.disapprove.size(); index++, extra += 4) { message << "How could I improve this site?\n" << " I have my own completely insane suggestion:\n" << " " << improve.disapprove[index] << "\n\n"; } message << "Make sure there were no errors.\n\n" << "------=_NextPart_WinXPFAQPoll_0\n" << "Content-Type: text/plain;\n" << " name=\"disapprove.dat\"\n" << "Content-Transfer-Encoding: 7bit\n" << "Content-Disposition: attachment;\n" << " filename=\"disapprove.dat\"\n\n"; if (find.disapprove.size() > 0) { message << "_find_\n"; extra++; } for (index = 0; index < find.disapprove.size(); index++, extra += 1) { message << find.disapprove[index] << "\n"; } if (improve.disapprove.size() > 0) { message << "_improve_\n"; extra++; } for (index = 0; index < improve.disapprove.size(); index++, extra += 1) { message << improve.disapprove[index] << "\n"; } message << "\n------=_NextPart_WinXPFAQPoll_0--\n"; ostringstream length; length << (message.str().length() + 26 + extra); session->append('\"' + account.getMailbox() + "\" {" + length.str() + '}', message.str()); session->noop(); cout << "done.\n"; } } short Poller::approval(const string& type, const string& text) { short answer = -1; stringstream search; search << session->search(string("ALL HEADER X-Mailer \"WinXPFAQPoll 1.0") + "\" SUBJECT \"Windows XP FAQ | Poll Submit\" FROM \"Windows XP FAQ |" + " Poll\" HEADER X-WinXPFAQPoll-Submit-Type \"" + type + "\" HEADER X" + "-WinXPFAQPoll-Submit-Text \"" + text + '\"'); search.ignore(9); search.peek(); if (search.good()) { unsigned message; search >> message; if (debug) cerr << "message = " << message << "\n"; ostringstream number; number << message; if (session->fetch(number.str() + " FLAGS").find("\\Deleted") != string::npos) { answer = false; } else if (session->fetch(number.str() + " FLAGS").find("\\Flagged") != string::npos) { answer = true; session->store(number.str() + " +FLAGS (\\Deleted)"); } } else { answer = false; } switch (answer) { case true: cout << "approved.\n"; break; case false: if (type == "find") { find.disapprove.push_back(text); } else if (type == "improve") { improve.disapprove.push_back(text); } cout << "disapproved.\n"; break; default: cout << "cancelled.\n"; break; } return answer; }