ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/Contactor.cpp
Revision: 107
Committed: 2003-03-31T20:39:56-08:00 (22 years, 2 months ago) by douglas
File size: 10747 byte(s)
Log Message:
Oops, I guess I need to finish fixing IMAPHandler first.

File Contents

# Content
1 /* ============================================================================
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(), true);
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 }