ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/Contactor.cpp
Revision: 104
Committed: 2003-03-31T20:18:26-08:00 (22 years, 2 months ago) by douglas
File size: 10760 byte(s)
Log Message:
Initial revision

File Contents

# User Rev Content
1 douglas 104 /* ============================================================================
2     * Douglas Thrift's Web Contact License
3     *
4     * Copyright (C) 2002, Douglas Thrift. All Rights Reserved.
5     *
6     * Redistribution and use in source and binary forms, with or without
7     * modification, are permitted provided that the following conditions are met:
8     *
9     * 1. Redistributions of source code must retain the above copyright notice,
10     * this list of conditions and the following disclaimer.
11     *
12     * 2. Redistributions in binary form must reproduce the above copyright notice,
13     * this list of conditions and the following disclaimer in the documentation
14     * and/or other materials provided with the distribution.
15     *
16     * 3. The end-user documentation included with the redistribution, if any, must
17     * include the following acknowledgment:
18     *
19     * "This product includes software developed by Douglas Thrift
20     * (http://computers.douglasthrift.net/webcontact.html)."
21     *
22     * Alternately, this acknowledgment may appear in the software itself, if
23     * and wherever such third-party acknowledgments normally appear.
24     *
25     * 4. The names "Douglas Thrift" and "Douglas Thrift's Web Contact" must not be
26     * used to endorse or promote products derived from this software without
27     * specific prior written permission. For written permission, please visit
28     * http://www.douglasthrift.net/contact.html for contact information.
29     *
30     * 5. Products derived from this software may not be called "Douglas Thrift's
31     * Web Contact", nor may "Douglas Thrift's Web Contact" appear in their
32     * name, without prior written permission.
33     *
34     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
35     * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36     * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37     * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
40     * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
41     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
43     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44     * ============================================================================
45     */
46     // Windows XP FAQ Poll
47     //
48     // Douglas Thrift
49     //
50     // Contactor.cpp
51    
52     #include "conio.h"
53     #include "Contactor.h"
54    
55     Contactor::Contactor()
56     {
57     loadAccount();
58    
59     if (debug)
60     {
61     cerr << "account = {\n host = " << account.getHost() << "\n "
62     << "port = " << account.getPort() << "\n "
63     << "name = " << account.getName() << "\n "
64     << "login = " << account.getLogin() << "\n "
65     << "email = " << account.getEmail() << "\n "
66     << "password = " << string(account.getPassword().length(), '*')
67     << "\n mailbox = " << account.getMailbox() << "\n}\n";
68     }
69    
70     session = new IMAPHandler(account.getHost(), account.getPort());
71    
72     if (session->capability().find("IMAP4rev1") == string::npos)
73     {
74     cerr << program << ": Server does not have IMAP4rev1 capability\n";
75    
76     exit(1);
77     }
78    
79     session->login(account.getLogin() + ' ' + account.getPassword());
80    
81     if (!session->successful())
82     {
83     cerr << program << ": Bad login or password\n";
84    
85     exit(1);
86     }
87     }
88    
89     Contactor::~Contactor()
90     {
91     session->logout();
92    
93     delete session;
94     }
95    
96     void Contactor::contact(bool nodelete)
97     {
98     this->nodelete = nodelete;
99    
100     fixMessages();
101     }
102    
103     void Contactor::saveAccount()
104     {
105     ifstream fin("account.dtd");
106    
107     bool exist = fin.is_open();
108    
109     if (debug) cerr << "exist = " << (exist ? "true" : "false") << "\n";
110    
111     if (!exist)
112     {
113     ofstream fout("account.dtd");
114    
115     fout << "<!ELEMENT account (host, port?, name, login, name, email, "
116     << "password?, mailbox?)>\n"
117     << "<!ELEMENT host (#PCDATA)>\n"
118     << "<!ELEMENT port (#PCDATA)>\n"
119     << "<!ELEMENT login (#PCDATA)>\n"
120     << "<!ELEMENT name (#PCDATA)>\n"
121     << "<!ELEMENT email (#PCDATA)>\n"
122     << "<!ELEMENT password (#PCDATA)>\n"
123     << "<!ELEMENT mailbox (#PCDATA)>\n";
124    
125     fout.close();
126     }
127     else
128     {
129     fin.close();
130     }
131    
132     Account account;
133    
134     cout << "Host: ";
135    
136     char* host = new char[1024];
137     cin.getline(host, 1024);
138    
139     account.setHost(host);
140     delete [] host;
141    
142     cout << "Port: ";
143    
144     char* port = new char[1024];
145     cin.getline(port, 1024);
146    
147     if (strlen(port) > 0) account.setPort(strtoul(port, 0, 0));
148     delete [] port;
149    
150     cout << "Login: ";
151    
152     char* login = new char[1024];
153     cin.getline(login, 1024);
154    
155     account.setLogin(login);
156     delete [] login;
157    
158     cout << "Name: ";
159    
160     char* name = new char[1024];
161     cin.getline(name, 1024);
162    
163     account.setName(name);
164     delete [] name;
165    
166     cout << "Email: ";
167    
168     char* email = new char[1024];
169     cin.getline(email, 1024);
170    
171     account.setEmail(email);
172     delete [] email;
173    
174     cout << "Password: " << flush;
175    
176     string password;
177    
178     char letter;
179     do
180     {
181     letter = _getch();
182    
183     if (letter == '\r' || letter == '\n')
184     {
185     cout << "\n";
186     }
187     else if (letter == '\b' && password.length() > 0)
188     {
189     cout << "\b \b";
190     password.erase(password.length() - 1);
191     }
192     else if (letter == '\b')
193     {
194     // do nothing
195     }
196     else
197     {
198     cout << '*';
199     password += letter;
200     }
201     }
202     while (letter != '\r' && letter != '\n');
203    
204     account.setPassword(password);
205    
206     cout << "Mailbox: ";
207    
208     char* mailbox = new char[1024];
209     cin.getline(mailbox, 1024);
210    
211     if (strlen(mailbox) > 0) account.setMailbox(mailbox);
212     delete [] mailbox;
213    
214     ofstream fout("account.xml");
215    
216     fout << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>"
217     << "\n<!DOCTYPE account SYSTEM \"account.dtd\">\n" << account << "\n";
218    
219     fout.close();
220     }
221    
222     void Contactor::loadAccount()
223     {
224     const string XMLTYPE = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" stan"
225     + string("dalone=\"no\"?>");
226     const string DOCTYPE = "<!DOCTYPE account SYSTEM \"account.dtd\">";
227    
228     ifstream fin("account.xml");
229    
230     if (!fin.is_open())
231     {
232     cerr << program << ": Could not open account file: account.xml\n";
233    
234     exit(1);
235     }
236    
237     string line;
238    
239     getline(fin, line);
240     if (line != XMLTYPE)
241     {
242     cerr << program << ": Invalid XML version declaration: account.xml\n";
243    
244     fin.close();
245     exit(1);
246     }
247    
248     getline(fin, line);
249     if (line != DOCTYPE)
250     {
251     cerr << program << ": Invalid XML doctype: account.xml\n";
252    
253     fin.close();
254     exit(1);
255     }
256    
257     fin >> account;
258    
259     if (account.getPassword() == "")
260     {
261     cout << "Password: " << flush;
262    
263     string password;
264    
265     char letter;
266     do
267     {
268     letter = _getch();
269    
270     if (letter == '\r' || letter == '\n')
271     {
272     cout << "\n";
273     }
274     else if (letter == '\b' && password.length() > 0)
275     {
276     cout << "\b \b";
277     password.erase(password.length() - 1);
278     }
279     else if (letter == '\b')
280     {
281     // do nothing
282     }
283     else
284     {
285     cout << '*';
286     password += letter;
287     }
288     }
289     while (letter != '\r' && letter != '\n');
290    
291     account.setPassword(password);
292     }
293     }
294    
295     void Contactor::fixMessages()
296     {
297     session->select("\"" + account.getMailbox() + "\"");
298    
299     if (!session->successful())
300     {
301     cerr << program << ": Bad mailbox name: " << account.getMailbox()
302     << "\n";
303     exit(1);
304     }
305    
306     string search = session->search("ALL FROM \"" + account.getEmail() + "\" "
307     + "BODY \"name = \" BODY \"email = \" BODY \"subject = \" "
308     + "BODY \"comments = \" BODY \"login = \" BODY \"REMOTE_HOST: \"");
309    
310     if (search.find("* SEARCH ") == 0)
311     {
312     messages;
313    
314     unsigned begin = 9;
315     do
316     {
317     unsigned end = search.find_first_of(" \r\n", begin);
318    
319     string message = search.substr(begin, end - begin);
320    
321     if (message != "")
322     {
323     if (debug) cerr << "message = " << message << "\n";
324     messages.push(message);
325     }
326    
327     if (end == string::npos) break;
328     begin = end + 1;
329     }
330     while (begin < search.length());
331    
332     if (!messages.empty())
333     {
334     string message = messages.front();
335     messages.pop();
336    
337     fixMessage(message);
338     }
339     }
340    
341     if (!nodelete)
342     {
343     session->expunge();
344     }
345     }
346    
347     void Contactor::fixMessage(const string& number)
348     {
349     cout << "Fixing message: " << number << "..." << flush;
350    
351     string header = session->fetch(number + " BODY.PEEK[HEADER]");
352     string text = session->fetch(number + " BODY.PEEK[TEXT]");
353    
354     Message message;
355     if (parseHeader(header, message) && parseText(text, message))
356     {
357     message.setMessage();
358    
359     session->append("\"" + account.getMailbox() + "\" \""
360     + message.getImapDate() + "\" {" + message.getLength() + '}',
361     message.getMessage());
362    
363     if (session->successful())
364     {
365     session->store(number + " +FLAGS (\\Deleted)");
366     cout << "done.\n";
367     }
368     else
369     {
370     cerr << program << ": Error storing message: " << number << "\n";
371     exit(1);
372     }
373     }
374     else
375     {
376     cout << "cancelled.\n";
377     }
378    
379     if (!messages.empty())
380     {
381     string next = messages.front();
382     messages.pop();
383    
384     fixMessage(next);
385     }
386     }
387    
388     bool Contactor::parseHeader(const string& header, Message& message)
389     {
390     bool answer = false;
391    
392     unsigned field = header.find("Date: ") + 6;
393     unsigned end = header.find("\r\n", field);
394    
395     string date = header.substr(field, end - field);
396     message.setDate(date);
397    
398     message.setTo("\"" + account.getName() + "\" <" + account.getEmail()
399     + '>');
400    
401     field = header.find("Subject: ") + 9;
402     end = header.find("\r\n", field);
403    
404     string subject = header.substr(field, end - field);
405     message.setSubject(subject);
406    
407     vector<string> recieved;
408     unsigned begin = 0;
409     do
410     {
411     field = header.find("Received: ", begin) + 10;
412     end = header.find("\r\n", field);
413    
414     if (field - 10 == string::npos) break;
415    
416     string value = header.substr(field, end - field);
417    
418     while (header[end + 2] == ' ' || header[end + 2] == ' ')
419     {
420     begin = end + 2;
421     end = header.find("\r\n", begin);
422    
423     value += "\r\n" + header.substr(begin, end - begin);
424     }
425    
426     recieved.push_back(value);
427    
428     if (end == string::npos) break;
429     begin = end + 1;
430     }
431     while (begin < header.length());
432     message.setRecieved(recieved);
433    
434     if (date != "" && recieved.size() > 0) answer = true;
435    
436     return answer;
437     }
438    
439     bool Contactor::parseText(const string& text, Message& message)
440     {
441     bool answer = false;
442    
443     unsigned field = text.find("name = ") + 7;
444     unsigned end = text.find("\r\nemail = ", field);
445    
446     string name = text.substr(field, end - field);
447    
448     field = end + 10;
449     end = text.find("\r\nsubject = ", field);
450    
451     string email = text.substr(field, end - field);
452    
453     message.setFrom("\"" + name + "\" <" + email + '>');
454    
455     field = end + 12;
456     end = text.find("\r\ncomments = ", field);
457    
458     string subject = text.substr(field, end - field);
459    
460     field = end + 13;
461     end = text.find("\r\nlogin = ", field);
462    
463     string comments = text.substr(field, end - field);
464     message.setText(comments);
465    
466     field = text.find("\r\nREMOTE_HOST: ", end) + 15;
467     end = text.find("\r\n", field);
468    
469     string host = text.substr(field, end - field);
470     message.setHost(host);
471    
472     if (subject == message.getSubject()) answer = true;
473    
474     return answer;
475     }