ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/Poller.cpp
Revision: 231
Committed: 2003-08-05T20:36:00-07:00 (21 years, 10 months ago) by douglas
File size: 13686 byte(s)
Log Message:
Maybe it will work now!

File Contents

# Content
1 // Windows XP FAQ Poll
2 //
3 // Douglas Thrift
4 //
5 // Poller.cpp
6
7 #include "Poller.h"
8
9 Poller::Poller()
10 {
11 string mailbox = session->list("\"\" \"" + account.getMailbox() + "\"");
12
13 if (mailbox.find(account.getMailbox()) == string::npos)
14 {
15 cerr << program << ": Mailbox does not exist: " << account.getMailbox()
16 << "\n";
17
18 exit(1);
19 }
20 }
21
22 Poller::~Poller()
23 {
24 if (!nodelete)
25 {
26 session->expunge();
27 }
28 }
29
30 void Poller::poll(bool nodelete, const string& file, bool approve)
31 {
32 this->nodelete = nodelete;
33 this->file = file;
34
35 load();
36
37 session->select('\"' + account.getMailbox() + '\"');
38
39 if (!approve)
40 {
41 ballots();
42 }
43 else
44 {
45 approvals();
46 }
47
48 save();
49 }
50
51 void Poller::load()
52 {
53 ifstream fin(file.c_str());
54 if (!fin.is_open())
55 {
56 fin.clear();
57
58 ofstream fout(file.c_str());
59
60 fout << "_find_\n"
61 << "reply=0\n"
62 << "news=0\n"
63 << "sig=0\n"
64 << "search=0\n"
65 << "link=0\n"
66 << "browse=0\n"
67 << "other=0\n"
68 << "_help_\n"
69 << "solved=0\n"
70 << "note=0\n"
71 << "link=0\n"
72 << "news=0\n"
73 << "lazy=0\n"
74 << "_improve_\n"
75 << "nothing=0\n"
76 << "links=0\n"
77 << "suggest=0\n";
78
79 fout.close();
80
81 fin.open(file.c_str());
82 }
83
84 while (fin.good())
85 {
86 enum { FIND, HELP, IMPROVE } type;
87 string vote;
88 unsigned count;
89 string text;
90
91 fin.peek() != '_' ? getline(fin, vote, '=') : getline(fin, vote);
92 if (debug) cerr << "vote = " << vote << "\n";
93
94 if (vote == "_find_")
95 {
96 type = FIND;
97 continue;
98 }
99 else if (vote == "_help_")
100 {
101 type = HELP;
102 continue;
103 }
104 else if (vote == "_improve_")
105 {
106 type = IMPROVE;
107 continue;
108 }
109 else if (vote == "approved" || vote == "approve")
110 {
111 getline(fin, text);
112 }
113 else
114 {
115 fin >> count;
116 fin.get();
117 }
118
119 if (fin.peek() == EOF) fin.get();
120
121 switch (type)
122 {
123 case FIND:
124 if (vote == "reply")
125 {
126 find.reply = count;
127 }
128 else if (vote == "news")
129 {
130 find.news = count;
131 }
132 else if (vote == "sig")
133 {
134 find.sig = count;
135 }
136 else if (vote == "search")
137 {
138 find.search = count;
139 }
140 else if (vote == "link")
141 {
142 find.link = count;
143 }
144 else if (vote == "browse")
145 {
146 find.browse = count;
147 }
148 else if (vote == "other")
149 {
150 find.other = count;
151 }
152 else if (vote == "approved")
153 {
154 find.approved.push_back(text);
155 }
156 else if (vote == "approve")
157 {
158 find.approve.push_back(text);
159 }
160 break;
161 case HELP:
162 if (vote == "solved")
163 {
164 help.solved = count;
165 }
166 else if (vote == "note")
167 {
168 help.note = count;
169 }
170 else if (vote == "link")
171 {
172 help.link = count;
173 }
174 else if (vote == "news")
175 {
176 help.news = count;
177 }
178 else if (vote == "lazy")
179 {
180 help.lazy = count;
181 }
182 break;
183 case IMPROVE:
184 if (vote == "nothing")
185 {
186 improve.nothing = count;
187 }
188 else if (vote == "links")
189 {
190 improve.links = count;
191 }
192 else if (vote == "suggest")
193 {
194 improve.suggest = count;
195 }
196 else if (vote == "approved")
197 {
198 improve.approved.push_back(text);
199 }
200 else if (vote == "approve")
201 {
202 improve.approve.push_back(text);
203 }
204 break;
205 }
206 }
207
208 fin.close();
209 }
210
211 void Poller::save()
212 {
213 unsigned index;
214 ofstream fout(file.c_str());
215
216 fout << "_find_\n"
217 << "reply=" << find.reply << "\n"
218 << "news=" << find.news << "\n"
219 << "sig=" << find.sig << "\n"
220 << "search=" << find.search << "\n"
221 << "link=" << find.link << "\n"
222 << "browse=" << find.browse << "\n"
223 << "other=" << find.other << "\n";
224
225 for (index = 0; index < find.approved.size(); index++)
226 {
227 fout << "approved=" << find.approved[index] << "\n";
228 }
229
230 for (index = 0; index < find.approve.size(); index++)
231 {
232 fout << "approve=" << find.approve[index] << "\n";
233 }
234
235 fout << "_help_\n"
236 << "solved=" << help.solved << "\n"
237 << "note=" << help.note << "\n"
238 << "link=" << help.link << "\n"
239 << "news=" << help.news << "\n"
240 << "lazy=" << help.lazy << "\n"
241 << "_improve_\n"
242 << "nothing=" << improve.nothing << "\n"
243 << "links=" << improve.links << "\n"
244 << "suggest=" << improve.suggest << "\n";
245
246 for (index = 0; index < improve.approved.size(); index++)
247 {
248 fout << "approved=" << improve.approved[index] << "\n";
249 }
250
251 for (index = 0; index < improve.approve.size(); index++)
252 {
253 fout << "approve=" << improve.approve[index] << "\n";
254 }
255
256 fout.close();
257 }
258
259 void Poller::ballots()
260 {
261 istringstream search(session->search(string("ALL HEADER X-Mailer \"WinXPFA")
262 + "QPoll 1.0 (Perl)\" SUBJECT \"Windows XP FAQ | Poll Ballot\" FROM \"W"
263 + "indows XP FAQ | Poll\""));
264
265 while (search.good())
266 {
267 char next = search.peek();
268
269 if (isdigit(next)) break;
270
271 search.get();
272 }
273
274 while (search.good())
275 {
276 unsigned message;
277 search >> message;
278
279 if (debug) cerr << "message = " << message << "\n";
280 messages.push(message);
281
282 search.get();
283
284 while (!isdigit(search.peek()) && search.good())
285 {
286 search.get();
287 }
288 }
289
290 if (!messages.empty())
291 {
292 unsigned message = messages.front();
293 messages.pop();
294
295 ballot(message);
296 }
297
298 if (submits.size() > 0)
299 {
300 cout << "Sending submits..." << flush;
301
302 for (unsigned index = 0; index < submits.size(); index++)
303 {
304 submit(submits[index].first, submits[index].second);
305 }
306
307 submits.clear();
308
309 cout << "done.\n";
310 }
311 }
312
313 void Poller::ballot(unsigned message)
314 {
315 cout << "Checking message: " << message << "..." << flush;
316
317 ostringstream number;
318 number << message;
319
320 string junk;
321 istringstream buffer(session->fetch(number.str() + " BODY.PEEK[2]"));
322
323 if (session->successful() && buffer.str() == "* " + number.str() + " FETCH"
324 + " (BODY[2] \"\")\n")
325 {
326 buffer.str(session->fetch(number.str() + " BODY.PEEK[TEXT]"));
327
328 for (unsigned index = 0; index < 25; index++)
329 {
330 getline(buffer, junk);
331 }
332 }
333
334 if (session->successful() && session->fetch(number.str() + " FLAGS").find(
335 "\\Deleted") == string::npos)
336 {
337 getline(buffer, junk);
338
339 bool approved = session->fetch(number.str() + " FLAGS").find("\\Flagge"
340 + string("d")) != string::npos;
341
342 while (buffer.peek() != '\n' && buffer.good())
343 {
344 enum { FIND, HELP, IMPROVE } type;
345 string vote;
346
347 getline(buffer, vote);
348 if (debug) cerr << "vote = " << vote << "\n";
349
350 if (vote == "_find_")
351 {
352 type = FIND;
353 continue;
354 }
355 else if (vote == "_help_")
356 {
357 type = HELP;
358 continue;
359 }
360 else if (vote == "_improve_")
361 {
362 type = IMPROVE;
363 continue;
364 }
365
366 buffer.peek();
367
368 switch (type)
369 {
370 case FIND:
371 if (vote == "reply")
372 {
373 find.reply++;
374 }
375 else if (vote == "news")
376 {
377 find.news++;
378 }
379 else if (vote == "sig")
380 {
381 find.sig++;
382 }
383 else if (vote == "search")
384 {
385 find.search++;
386 }
387 else if (vote == "link")
388 {
389 find.link++;
390 }
391 else if (vote == "browse")
392 {
393 find.browse++;
394 }
395 else if (vote == "other")
396 {
397 find.other++;
398
399 string text;
400 getline(buffer, text);
401
402 if (approved)
403 {
404 find.approved.push_back(text);
405 }
406 else
407 {
408 find.approve.push_back(text);
409
410 submits.push_back(pair<string, string>("find", text));
411 }
412 }
413 break;
414 case HELP:
415 if (vote == "solved")
416 {
417 help.solved++;
418 }
419 else if (vote == "note")
420 {
421 help.note++;
422 }
423 else if (vote == "link")
424 {
425 help.link++;
426 }
427 else if (vote == "news")
428 {
429 help.news++;
430 }
431 else if (vote == "lazy")
432 {
433 help.lazy++;
434 }
435 break;
436 case IMPROVE:
437 if (vote == "nothing")
438 {
439 improve.nothing++;
440 }
441 else if (vote == "links")
442 {
443 improve.links++;
444 }
445 else if (vote == "suggest")
446 {
447 improve.suggest++;
448
449 string text;
450 getline(buffer, text);
451
452 if (approved)
453 {
454 improve.approved.push_back(text);
455 }
456 else
457 {
458 improve.approve.push_back(text);
459
460 submits.push_back(pair<string, string>("improve",
461 text));
462 }
463 }
464 break;
465 }
466 }
467
468 session->store(number.str() + " +FLAGS (\\Deleted)");
469
470 cout << "done.\n";
471 }
472 else
473 {
474 cout << "cancelled.\n";
475 }
476
477 if (!messages.empty())
478 {
479 unsigned message = messages.front();
480 messages.pop();
481
482 ballot(message);
483 }
484 }
485
486 void Poller::submit(const string& type, const string& text)
487 {
488 ostringstream message;
489
490 message << "From: \"Windows XP FAQ | Poll\" <" << account.getEmail()
491 << ">\n"
492 << "To: \"" << account.getName() << "\" <" << account.getEmail()
493 << ">\n"
494 << "Subject: Windows XP FAQ | Poll Submit\n"
495 << "Content-Type: text/plain charset=\"us-ascii\"\n"
496 << "Content-Transfer-Encoding: 7bit\n"
497 << "X-Mailer: WinXPFAQPoll 1.0\n"
498 << "X-WinXPFAQPoll-Submit-Type: " << type << "\n"
499 << "X-WinXPFAQPoll-Submit-Text: " << text << "\n\n";
500
501 if (type == "find")
502 {
503 message << "How did you find this page?\n"
504 << " I arrived here by entirely different means:\n";
505 }
506 else if (type == "improve")
507 {
508 message << "How could I improve this site?\n"
509 << " I have my own completely insane suggestion:\n";
510 }
511
512 message << " " << text << "\n\n"
513 << "Flag this message to approve the voter\'s possibly objectionable\n"
514 << "input or delete it to disapprove.\n\n"
515 << "This message will be marked deleted when it is processed.\n";
516
517 ostringstream length;
518 length << (message.str().length() + 16);
519
520 session->append('\"' + account.getMailbox() + "\" {" + length.str() + '}',
521 message.str());
522
523 session->noop();
524 }
525
526 void Poller::approvals()
527 {
528 session->check();
529
530 unsigned index;
531
532 for (index = find.approve.size(); index > 0; index--)
533 {
534 cout << "Checking find: " << index << "..." << flush;
535
536 switch (approval("find", find.approve[index - 1]))
537 {
538 case true:
539 find.approved.push_back(find.approve[index - 1]);
540 case false:
541 find.approve.erase(find.approve.begin() + (index - 1));
542 break;
543 default:
544 break;
545 }
546 }
547
548 for (index = improve.approve.size(); index > 0; index--)
549 {
550 cout << "Checking improve: " << index << "..." << flush;
551
552 switch (approval("improve", improve.approve[index - 1]))
553 {
554 case true:
555 improve.approved.push_back(improve.approve[index - 1]);
556 case false:
557 improve.approve.erase(improve.approve.begin() + (index - 1));
558 break;
559 default:
560 break;
561 }
562 }
563
564 if (find.disapprove.size() > 0 || improve.disapprove.size() > 0)
565 {
566 cout << "Sending disapprovals..." << flush;
567
568 ostringstream message;
569
570 message << "From: \"Windows XP FAQ | Poll\" <" << account.getEmail()
571 << ">\n"
572 << "To: \"" << account.getName() << "\" <" << account.getEmail()
573 << ">\n"
574 << "Subject: Windows XP FAQ | Poll Disapprovals\n"
575 << "Content-Type: multipart/mixed;\n"
576 << " boundary=\"----=_NextPart_WinXPFAQPoll_0\"\n"
577 << "Content-Transfer-Encoding: 7bit\n"
578 << "X-Mailer: WinXPFAQPoll 1.0\n\n"
579 << "This is a multi-part message in MIME format.\n\n"
580 << "------=_NextPart_WinXPFAQPoll_0\n"
581 << "Content-Type: text/plain charset=\"us-ascii\"\n"
582 << "Content-Transfer-Encoding: 7bit\n\n"
583 << "Apparently these answers where disapproved:\n\n";
584
585 unsigned extra = 0;
586
587 for (index = 0; index < find.disapprove.size(); index++, extra += 4)
588 {
589 message << "How did you find this page?\n"
590 << " I arrived here by entirely different means:\n"
591 << " " << find.disapprove[index] << "\n\n";
592 }
593
594 for (index = 0; index < improve.disapprove.size(); index++, extra += 4)
595 {
596 message << "How could I improve this site?\n"
597 << " I have my own completely insane suggestion:\n"
598 << " " << improve.disapprove[index] << "\n\n";
599 }
600
601 message << "Make sure there were no errors.\n\n"
602 << "------=_NextPart_WinXPFAQPoll_0\n"
603 << "Content-Type: text/plain;\n"
604 << " name=\"disapprove.dat\"\n"
605 << "Content-Transfer-Encoding: 7bit\n"
606 << "Content-Disposition: attachment;\n"
607 << " filename=\"disapprove.dat\"\n\n";
608
609 if (find.disapprove.size() > 0)
610 {
611 message << "_find_\n";
612 extra++;
613 }
614
615 for (index = 0; index < find.disapprove.size(); index++, extra += 1)
616 {
617 message << find.disapprove[index] << "\n";
618 }
619
620 if (improve.disapprove.size() > 0)
621 {
622 message << "_improve_\n";
623 extra++;
624 }
625
626 for (index = 0; index < improve.disapprove.size(); index++, extra += 1)
627 {
628 message << improve.disapprove[index] << "\n";
629 }
630
631 message << "\n------=_NextPart_WinXPFAQPoll_0--\n";
632
633 ostringstream length;
634 length << (message.str().length() + 26 + extra);
635
636 session->append('\"' + account.getMailbox() + "\" {" + length.str() +
637 '}', message.str());
638
639 session->noop();
640
641 cout << "done.\n";
642 }
643 }
644
645 short Poller::approval(const string& type, const string& text)
646 {
647 short answer = -1;
648
649 istringstream search(session->search(string("ALL HEADER X-Mailer \"WinXPF")
650 + "AQPoll 1.0\" SUBJECT \"Windows XP FAQ | Poll Submit\" FROM \"Window"
651 + "s XP FAQ | Poll\" HEADER X-WinXPFAQPoll-Submit-Type \"" + type
652 + "\" HEADER X-WinXPFAQPoll-Submit-Text \"" + text + '\"'));
653
654 while (search.good())
655 {
656 char next = search.peek();
657
658 if (isdigit(next)) break;
659
660 search.get();
661 }
662
663 if (search.good())
664 {
665 unsigned message;
666 search >> message;
667
668 if (debug) cerr << "message = " << message << "\n";
669
670 ostringstream number;
671 number << message;
672
673 if (session->fetch(number.str() + " FLAGS").find("\\Deleted") !=
674 string::npos)
675 {
676 answer = false;
677 }
678 else if (session->fetch(number.str() + " FLAGS").find("\\Flagged") !=
679 string::npos)
680 {
681 answer = true;
682
683 session->store(number.str() + " +FLAGS (\\Deleted)");
684 }
685 }
686 else
687 {
688 answer = false;
689 }
690
691 switch (answer)
692 {
693 case true:
694 cout << "approved.\n";
695 break;
696 case false:
697 if (type == "find")
698 {
699 find.disapprove.push_back(text);
700 }
701 else if (type == "improve")
702 {
703 improve.disapprove.push_back(text);
704 }
705 cout << "disapproved.\n";
706 break;
707 default:
708 cout << "cancelled.\n";
709 break;
710 }
711
712 return answer;
713 }