ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/IMAPHandler.cpp
Revision: 116
Committed: 2003-04-01T00:43:13-08:00 (22 years, 2 months ago) by douglas
File size: 12856 byte(s)
Log Message:
That is better.

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 // IMAPHandler.cpp
51
52 #include "IMAPHandler.h"
53
54 IMAPHandler::IMAPHandler(const string& server, bool tls)
55 {
56 letter = 'a';
57 number = 0;
58
59 this->tls = tls;
60 buffer = new char[BUFSIZ + 1];
61
62 #ifdef _WIN32
63 if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
64 {
65 error(program + ": WSAStartup");
66 exit(1);
67 }
68 #endif // _WIN32
69
70 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
71 {
72 error(program + ": Socket");
73 exit(1);
74 }
75
76 sockaddr_in address;
77 hostent* host;
78
79 address.sin_family = AF_INET;
80
81 if ((host = gethostbyname(server.c_str())) == NULL)
82 {
83 error(program + ": Host: " + server, true);
84 exit(1);
85 }
86
87 address.sin_addr = *((in_addr*)*host->h_addr_list);
88 address.sin_port = htons(tls ? 993 : 143);
89
90 if (connect(sock, (sockaddr*)&address, sizeof(sockaddr_in)) ==
91 SOCKET_ERROR)
92 {
93 error(program + ": Connect");
94 exit(1);
95 }
96
97 if (tls)
98 {
99 SSL_load_error_strings();
100 SSL_library_init();
101
102 char* seed = new char[BUFSIZ + 1];
103 time_t moment = time(NULL);
104 sprintf(seed, "froofy%sfoofoo", ctime(&moment));
105
106 RAND_add(seed, strlen(seed), 0.007456);
107
108 delete [] seed;
109
110 ctx = SSL_CTX_new(TLSv1_client_method());
111 if (ctx == NULL)
112 {
113 cerr << program << ": SSL CTX New: " <<
114 ERR_reason_error_string(ERR_get_error()) << "\n";
115 exit(1);
116 }
117
118 ssl = SSL_new(ctx);
119
120 if (SSL_set_fd(ssl, sock) == 0)
121 {
122 cerr << program << ": SSL Set FD: " <<
123 ERR_reason_error_string(ERR_get_error()) << "\n";
124 exit(1);
125 }
126
127 if (int code = SSL_connect(ssl) <= 0)
128 {
129 error(program + ": SSL Connect", code);
130 exit(1);
131 }
132 }
133
134 getline();
135 }
136
137 IMAPHandler::~IMAPHandler()
138 {
139 if (tls)
140 {
141 SSL_shutdown(ssl);
142 SSL_free(ssl);
143 SSL_CTX_free(ctx);
144 }
145
146 closesocket(sock);
147
148 delete [] buffer;
149
150 #ifdef _WIN32
151 WSACleanup();
152 #endif // _WIN32
153 }
154
155 string IMAPHandler::starttls()
156 {
157 string answer = imap("STARTTLS");
158
159 if (success)
160 {
161 tls = true;
162
163 SSL_load_error_strings();
164 SSL_library_init();
165
166 char* seed = new char[BUFSIZ + 1];
167 time_t moment = time(NULL);
168 sprintf(seed, "froofy%sfoofoo", ctime(&moment));
169
170 RAND_add(seed, strlen(seed), 0.007456);
171
172 delete [] seed;
173
174 ctx = SSL_CTX_new(TLSv1_client_method());
175 if (ctx == NULL)
176 {
177 cerr << program << ": SSL CTX New: " <<
178 ERR_reason_error_string(ERR_get_error()) << "\n";
179 exit(1);
180 }
181
182 ssl = SSL_new(ctx);
183
184 if (SSL_set_fd(ssl, sock) == 0)
185 {
186 cerr << program << ": SSL Set FD: " <<
187 ERR_reason_error_string(ERR_get_error()) << "\n";
188 exit(1);
189 }
190
191 if (int code = SSL_connect(ssl) <= 0)
192 {
193 error(program + ": SSL Connect", code);
194 exit(1);
195 }
196 }
197
198 return answer;
199 }
200
201 string IMAPHandler::command()
202 {
203 char buffer[4];
204 sprintf(buffer, "%03u", number++);
205
206 string sequence = letter + string(buffer);
207
208 if (number > 999)
209 {
210 letter++;
211 number = 0;
212 }
213
214 if (letter > 'z')
215 {
216 letter = 'a';
217 }
218
219 return sequence;
220 }
221
222 string IMAPHandler::imap(const string& imap)
223 {
224 string result;
225
226 string sequence = command();
227 putline(sequence + " " + imap);
228
229 while (true)
230 {
231 string input = getline();
232
233 if (input.find(sequence + " OK") == 0)
234 {
235 success = true;
236 break;
237 }
238 else if (input.find(sequence + " NO") == 0 || input.find(sequence +
239 " BAD") == 0)
240 {
241 success = false;
242 break;
243 }
244 else
245 {
246 result += input + "\r\n";
247 }
248 }
249
250 return result;
251 }
252
253 string IMAPHandler::imap(const string& imap, const string& args)
254 {
255 string result;
256
257 string sequence = command();
258 putline(sequence + " " + imap + " " + args);
259
260 while (true)
261 {
262 string input = getline();
263
264 if (input.find(sequence + " OK") == 0)
265 {
266 success = true;
267 break;
268 }
269 else if (input.find(sequence + " NO") == 0 || input.find(sequence +
270 " BAD") == 0)
271 {
272 success = false;
273 break;
274 }
275 else
276 {
277 result += input + "\r\n";
278 }
279 }
280
281 return result;
282 }
283
284 string IMAPHandler::imap(const string& imap, const string& args, const string&
285 message)
286 {
287 string result;
288
289 string sequence = command();
290 putline(sequence + " " + imap + " " + args);
291 putline(message);
292
293 while (true)
294 {
295 string input = getline();
296
297 if (input.find(sequence + " OK") == 0)
298 {
299 success = true;
300 break;
301 }
302 else if (input.find(sequence + " NO") == 0 || input.find(sequence +
303 " BAD") == 0)
304 {
305 success = false;
306 break;
307 }
308 else
309 {
310 result += input + "\r\n";
311 }
312 }
313
314 return result;
315 }
316
317 void IMAPHandler::putline(const string line)
318 {
319 if (debug) cerr << line << "\n";
320
321 sprintf(buffer, "%s\r\n", line.c_str());
322
323 if (tls)
324 {
325 if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
326 {
327 error(program + ": SSL Write", code);
328 exit(1);
329 }
330 }
331 else
332 {
333 if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
334 {
335 error(program + ": Send");
336 exit(1);
337 }
338 }
339 }
340
341 string IMAPHandler::getline()
342 {
343 string line;
344 char byte;
345
346 do
347 {
348 if (tls)
349 {
350 if (int code = SSL_read(ssl, &byte, 1) <= 0)
351 {
352 error(program + ": SSL Read", code);
353 exit(1);
354 }
355 }
356 else
357 {
358 if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
359 {
360 error(program + ": Recv");
361 exit(1);
362 }
363 }
364
365 if (byte != '\r' && byte != '\n')
366 {
367 line += byte;
368 }
369 }
370 while (byte != '\n');
371
372 if (debug) cerr << line << "\n";
373
374 return line;
375 }
376
377 void IMAPHandler::error(const string& prefix, bool host)
378 {
379 #ifdef _WIN32
380 string error;
381
382 switch (WSAGetLastError())
383 {
384 case WSAEACCES:
385 error = "Permission denied.";
386 break;
387 case WSAEADDRINUSE:
388 error = "Address already in use.";
389 break;
390 case WSAEADDRNOTAVAIL:
391 error = "Cannot assign requested address.";
392 break;
393 case WSAEAFNOSUPPORT:
394 error = "Address family not supported by protocol family.";
395 break;
396 case WSAEALREADY:
397 error = "Operation already in progress.";
398 break;
399 case WSAECONNABORTED:
400 error = "Software caused connection abort.";
401 break;
402 case WSAECONNREFUSED:
403 error = "Connection refused.";
404 break;
405 case WSAECONNRESET:
406 error = "Connection reset by peer.";
407 break;
408 case WSAEDESTADDRREQ:
409 error = "Destination address required.";
410 break;
411 case WSAEFAULT:
412 error = "Bad address.";
413 break;
414 case WSAEHOSTDOWN:
415 error = "Host is down.";
416 break;
417 case WSAEHOSTUNREACH:
418 error = "No route to host.";
419 break;
420 case WSAEINPROGRESS:
421 error = "Operation now in progress.";
422 break;
423 case WSAEINTR:
424 error = "Interrupted function call.";
425 break;
426 case WSAEINVAL:
427 error = "Invalid argument.";
428 break;
429 case WSAEISCONN:
430 error = "Socket is already connected.";
431 break;
432 case WSAEMFILE:
433 error = "Too many open files.";
434 break;
435 case WSAEMSGSIZE:
436 error = "Message too long.";
437 break;
438 case WSAENETDOWN:
439 error = "Network is down.";
440 break;
441 case WSAENETRESET:
442 error = "Network dropped connection on reset.";
443 break;
444 case WSAENETUNREACH:
445 error = "Network is unreachable.";
446 break;
447 case WSAENOBUFS:
448 error = "No buffer space available.";
449 break;
450 case WSAENOPROTOOPT:
451 error = "Bad protocol option.";
452 break;
453 case WSAENOTCONN:
454 error = "Socket is not connected.";
455 break;
456 case WSAENOTSOCK:
457 error = "Socket operation on non-socket.";
458 break;
459 case WSAEOPNOTSUPP:
460 error = "Operation not supported.";
461 break;
462 case WSAEPFNOSUPPORT:
463 error = "Protocol family not supported.";
464 break;
465 case WSAEPROCLIM:
466 error = "Too many processes.";
467 break;
468 case WSAEPROTONOSUPPORT:
469 error = "Protocol not supported.";
470 break;
471 case WSAEPROTOTYPE:
472 error = "Protocol wrong type for socket.";
473 break;
474 case WSAESHUTDOWN:
475 error = "Cannot send after socket shutdown.";
476 break;
477 case WSAESOCKTNOSUPPORT:
478 error = "Socket type not supported.";
479 break;
480 case WSAETIMEDOUT:
481 error = "Connection timed out.";
482 break;
483 case WSATYPE_NOT_FOUND:
484 error = "Class type not found.";
485 break;
486 case WSAEWOULDBLOCK:
487 error = "Resource temporarily unavailable.";
488 break;
489 case WSAHOST_NOT_FOUND:
490 error = "Host not found.";
491 break;
492 case WSA_INVALID_HANDLE:
493 error = "Specified event object handle is invalid.";
494 break;
495 case WSA_INVALID_PARAMETER:
496 error = "One or more parameters are invalid.";
497 break;
498 // case WSAINVALIDPROCTABLE:
499 // error = "Invalid procedure table from service provider.";
500 // break;
501 // case WSAINVALIDPROVIDER:
502 // error = "Invalid service provider version number.";
503 // break;
504 case WSA_IO_INCOMPLETE:
505 error = "Overlapped I/O event object not in signaled state.";
506 break;
507 case WSA_IO_PENDING:
508 error = "Overlapped operations will complete later.";
509 break;
510 case WSA_NOT_ENOUGH_MEMORY:
511 error = "Insufficient memory available.";
512 break;
513 case WSANOTINITIALISED:
514 error = "Successful WSAStartup not yet performed.";
515 break;
516 case WSANO_DATA:
517 error = "Valid name, no data record of requested type.";
518 break;
519 case WSANO_RECOVERY:
520 error = "This is a non-recoverable error.";
521 break;
522 // case WSAPROVIDERFAILEDINIT:
523 // error = "Unable to initialize a service provider.";
524 // break;
525 case WSASYSCALLFAILURE:
526 error = "System call failure.";
527 break;
528 case WSASYSNOTREADY:
529 error = "Network subsystem is unavailable.";
530 break;
531 case WSATRY_AGAIN:
532 error = "Non-authoritative host not found.";
533 break;
534 case WSAVERNOTSUPPORTED:
535 error = "WINSOCK.DLL version out of range.";
536 break;
537 case WSAEDISCON:
538 error = "Graceful shutdown in progress.";
539 break;
540 case WSA_OPERATION_ABORTED:
541 error = "Overlapped operation aborted.";
542 break;
543 default:
544 error = "Unknown error.";
545 break;
546 }
547
548 cerr << prefix << ": " << error << "\n";
549 #else
550 if (host)
551 {
552 herror(prefix.c_str());
553 }
554 else
555 {
556 perror(prefix.c_str());
557 }
558 #endif // _WIN32
559 }
560
561 void IMAPHandler::error(const string& prefix, int code)
562 {
563 string error;
564
565 switch (SSL_get_error(ssl, code))
566 {
567 case SSL_ERROR_NONE:
568 error = "The TLS/SSL I/O operation completed.";
569 break;
570 case SSL_ERROR_ZERO_RETURN:
571 error = "The TLS/SSL connection has been closed.";
572 break;
573 case SSL_ERROR_WANT_READ:
574 case SSL_ERROR_WANT_WRITE:
575 case SSL_ERROR_WANT_CONNECT:
576 // case SSL_ERROR_WANT_ACCEPT:
577 case SSL_ERROR_WANT_X509_LOOKUP:
578 error = "The operation did not complete.";
579 break;
580 case SSL_ERROR_SYSCALL:
581 if (int err = ERR_get_error() != 0)
582 {
583 error = ERR_reason_error_string(err);
584 }
585 else
586 {
587 switch (code)
588 {
589 case 0:
590 error = "An EOF was observed that violates the protocol.";
591 break;
592 case -1:
593 this->error(prefix);
594 return;
595 default:
596 error = "Unknown error.";
597 break;
598 }
599 }
600 break;
601 case SSL_ERROR_SSL:
602 error = ERR_reason_error_string(ERR_get_error());
603 break;
604 default:
605 error = "Unknown error.";
606 break;
607 }
608
609 cerr << prefix << ": " << error << "\n";
610 }