/* ============================================================================ * Douglas Thrift's Web Contact License * * Copyright (C) 2002, Douglas Thrift. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: * * "This product includes software developed by Douglas Thrift * (http://computers.douglasthrift.net/webcontact.html)." * * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "Douglas Thrift" and "Douglas Thrift's Web Contact" must not be * used to endorse or promote products derived from this software without * specific prior written permission. For written permission, please visit * http://www.douglasthrift.net/contact.html for contact information. * * 5. Products derived from this software may not be called "Douglas Thrift's * Web Contact", nor may "Douglas Thrift's Web Contact" appear in their * name, without prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================ */ // Windows XP FAQ Poll // // Douglas Thrift // // Contactor.cpp #include "conio.h" #include "Contactor.h" Contactor::Contactor() { loadAccount(); if (debug) { cerr << "account = {\n host = " << account.getHost() << "\n " << "port = " << account.getPort() << "\n " << "name = " << account.getName() << "\n " << "login = " << account.getLogin() << "\n " << "email = " << account.getEmail() << "\n " << "password = " << string(account.getPassword().length(), '*') << "\n mailbox = " << account.getMailbox() << "\n}\n"; } session = new IMAPHandler(account.getHost(), true); if (session->capability().find("IMAP4rev1") == string::npos) { cerr << program << ": Server does not have IMAP4rev1 capability\n"; exit(1); } session->login(account.getLogin() + ' ' + account.getPassword()); if (!session->successful()) { cerr << program << ": Bad login or password\n"; exit(1); } } Contactor::~Contactor() { session->logout(); delete session; } void Contactor::contact(bool nodelete) { this->nodelete = nodelete; fixMessages(); } void Contactor::saveAccount() { ifstream fin("account.dtd"); bool exist = fin.is_open(); if (debug) cerr << "exist = " << (exist ? "true" : "false") << "\n"; if (!exist) { ofstream fout("account.dtd"); fout << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n"; fout.close(); } else { fin.close(); } Account account; cout << "Host: "; char* host = new char[1024]; cin.getline(host, 1024); account.setHost(host); delete [] host; cout << "Port: "; char* port = new char[1024]; cin.getline(port, 1024); if (strlen(port) > 0) account.setPort(strtoul(port, 0, 0)); delete [] port; cout << "Login: "; char* login = new char[1024]; cin.getline(login, 1024); account.setLogin(login); delete [] login; cout << "Name: "; char* name = new char[1024]; cin.getline(name, 1024); account.setName(name); delete [] name; cout << "Email: "; char* email = new char[1024]; cin.getline(email, 1024); account.setEmail(email); delete [] email; cout << "Password: " << flush; string password; char letter; do { letter = _getch(); if (letter == '\r' || letter == '\n') { cout << "\n"; } else if (letter == '\b' && password.length() > 0) { cout << "\b \b"; password.erase(password.length() - 1); } else if (letter == '\b') { // do nothing } else { cout << '*'; password += letter; } } while (letter != '\r' && letter != '\n'); account.setPassword(password); cout << "Mailbox: "; char* mailbox = new char[1024]; cin.getline(mailbox, 1024); if (strlen(mailbox) > 0) account.setMailbox(mailbox); delete [] mailbox; ofstream fout("account.xml"); fout << "" << "\n\n" << account << "\n"; fout.close(); } void Contactor::loadAccount() { const string XMLTYPE = ""); const string DOCTYPE = ""; ifstream fin("account.xml"); if (!fin.is_open()) { cerr << program << ": Could not open account file: account.xml\n"; exit(1); } string line; getline(fin, line); if (line != XMLTYPE) { cerr << program << ": Invalid XML version declaration: account.xml\n"; fin.close(); exit(1); } getline(fin, line); if (line != DOCTYPE) { cerr << program << ": Invalid XML doctype: account.xml\n"; fin.close(); exit(1); } fin >> account; if (account.getPassword() == "") { cout << "Password: " << flush; string password; char letter; do { letter = _getch(); if (letter == '\r' || letter == '\n') { cout << "\n"; } else if (letter == '\b' && password.length() > 0) { cout << "\b \b"; password.erase(password.length() - 1); } else if (letter == '\b') { // do nothing } else { cout << '*'; password += letter; } } while (letter != '\r' && letter != '\n'); account.setPassword(password); } } void Contactor::fixMessages() { session->select("\"" + account.getMailbox() + "\""); if (!session->successful()) { cerr << program << ": Bad mailbox name: " << account.getMailbox() << "\n"; exit(1); } string search = session->search("ALL FROM \"" + account.getEmail() + "\" " + "BODY \"name = \" BODY \"email = \" BODY \"subject = \" " + "BODY \"comments = \" BODY \"login = \" BODY \"REMOTE_HOST: \""); if (search.find("* SEARCH ") == 0) { messages; unsigned begin = 9; do { unsigned end = search.find_first_of(" \r\n", begin); string message = search.substr(begin, end - begin); if (message != "") { if (debug) cerr << "message = " << message << "\n"; messages.push(message); } if (end == string::npos) break; begin = end + 1; } while (begin < search.length()); if (!messages.empty()) { string message = messages.front(); messages.pop(); fixMessage(message); } } if (!nodelete) { session->expunge(); } } void Contactor::fixMessage(const string& number) { cout << "Fixing message: " << number << "..." << flush; string header = session->fetch(number + " BODY.PEEK[HEADER]"); string text = session->fetch(number + " BODY.PEEK[TEXT]"); Message message; if (parseHeader(header, message) && parseText(text, message)) { message.setMessage(); session->append("\"" + account.getMailbox() + "\" \"" + message.getImapDate() + "\" {" + message.getLength() + '}', message.getMessage()); if (session->successful()) { session->store(number + " +FLAGS (\\Deleted)"); cout << "done.\n"; } else { cerr << program << ": Error storing message: " << number << "\n"; exit(1); } } else { cout << "cancelled.\n"; } if (!messages.empty()) { string next = messages.front(); messages.pop(); fixMessage(next); } } bool Contactor::parseHeader(const string& header, Message& message) { bool answer = false; unsigned field = header.find("Date: ") + 6; unsigned end = header.find("\r\n", field); string date = header.substr(field, end - field); message.setDate(date); message.setTo("\"" + account.getName() + "\" <" + account.getEmail() + '>'); field = header.find("Subject: ") + 9; end = header.find("\r\n", field); string subject = header.substr(field, end - field); message.setSubject(subject); vector recieved; unsigned begin = 0; do { field = header.find("Received: ", begin) + 10; end = header.find("\r\n", field); if (field - 10 == string::npos) break; string value = header.substr(field, end - field); while (header[end + 2] == ' ' || header[end + 2] == ' ') { begin = end + 2; end = header.find("\r\n", begin); value += "\r\n" + header.substr(begin, end - begin); } recieved.push_back(value); if (end == string::npos) break; begin = end + 1; } while (begin < header.length()); message.setRecieved(recieved); if (date != "" && recieved.size() > 0) answer = true; return answer; } bool Contactor::parseText(const string& text, Message& message) { bool answer = false; unsigned field = text.find("name = ") + 7; unsigned end = text.find("\r\nemail = ", field); string name = text.substr(field, end - field); field = end + 10; end = text.find("\r\nsubject = ", field); string email = text.substr(field, end - field); message.setFrom("\"" + name + "\" <" + email + '>'); field = end + 12; end = text.find("\r\ncomments = ", field); string subject = text.substr(field, end - field); field = end + 13; end = text.find("\r\nlogin = ", field); string comments = text.substr(field, end - field); message.setText(comments); field = text.find("\r\nREMOTE_HOST: ", end) + 15; end = text.find("\r\n", field); string host = text.substr(field, end - field); message.setHost(host); if (subject == message.getSubject()) answer = true; return answer; }