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

# 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     // IMAPHandler.cpp
51    
52     #include "IMAPHandler.h"
53    
54 douglas 107 IMAPHandler::IMAPHandler(const string& server, bool tls)
55     {
56 douglas 116 letter = 'a';
57     number = 0;
58    
59 douglas 107 this->tls = tls;
60     buffer = new char[BUFSIZ + 1];
61    
62 douglas 104 #ifdef _WIN32
63 douglas 107 if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
64     {
65     error(program + ": WSAStartup");
66     exit(1);
67     }
68     #endif // _WIN32
69 douglas 104
70 douglas 107 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 douglas 104
79 douglas 107 address.sin_family = AF_INET;
80 douglas 104
81 douglas 107 if ((host = gethostbyname(server.c_str())) == NULL)
82     {
83     error(program + ": Host: " + server, true);
84     exit(1);
85     }
86 douglas 104
87 douglas 107 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 douglas 104 {
93 douglas 107 error(program + ": Connect");
94     exit(1);
95     }
96 douglas 104
97 douglas 107 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 douglas 104 {
113 douglas 107 cerr << program << ": SSL CTX New: " <<
114     ERR_reason_error_string(ERR_get_error()) << "\n";
115     exit(1);
116     }
117 douglas 104
118 douglas 107 ssl = SSL_new(ctx);
119 douglas 104
120 douglas 107 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 douglas 104 }
126 douglas 107
127     if (int code = SSL_connect(ssl) <= 0)
128     {
129     error(program + ": SSL Connect", code);
130     exit(1);
131     }
132 douglas 104 }
133 douglas 107
134 douglas 116 getline();
135 douglas 104 }
136    
137     IMAPHandler::~IMAPHandler()
138     {
139 douglas 107 if (tls)
140 douglas 104 {
141 douglas 107 SSL_shutdown(ssl);
142     SSL_free(ssl);
143     SSL_CTX_free(ctx);
144 douglas 104 }
145 douglas 107
146     closesocket(sock);
147    
148     delete [] buffer;
149    
150     #ifdef _WIN32
151     WSACleanup();
152     #endif // _WIN32
153 douglas 104 }
154    
155 douglas 107 string IMAPHandler::starttls()
156 douglas 104 {
157 douglas 107 string answer = imap("STARTTLS");
158 douglas 104
159 douglas 107 if (success)
160 douglas 104 {
161 douglas 116 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 douglas 104 }
197    
198     return answer;
199     }
200    
201 douglas 116 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 douglas 107 string IMAPHandler::imap(const string& imap)
223 douglas 104 {
224 douglas 107 string result;
225 douglas 104
226 douglas 116 string sequence = command();
227     putline(sequence + " " + imap);
228 douglas 107
229 douglas 116 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 douglas 107 return result;
251     }
252    
253 douglas 116 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 douglas 107 void IMAPHandler::putline(const string line)
318     {
319 douglas 116 if (debug) cerr << line << "\n";
320    
321 douglas 107 sprintf(buffer, "%s\r\n", line.c_str());
322    
323     if (tls)
324 douglas 104 {
325 douglas 107 if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
326 douglas 104 {
327 douglas 107 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 douglas 104
341 douglas 107 string IMAPHandler::getline()
342     {
343     string line;
344     char byte;
345 douglas 104
346 douglas 107 do
347     {
348     if (tls)
349     {
350     if (int code = SSL_read(ssl, &byte, 1) <= 0)
351 douglas 104 {
352 douglas 107 error(program + ": SSL Read", code);
353 douglas 104 exit(1);
354     }
355     }
356     else
357     {
358 douglas 107 if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
359 douglas 104 {
360 douglas 107 error(program + ": Recv");
361 douglas 104 exit(1);
362     }
363     }
364    
365 douglas 107 if (byte != '\r' && byte != '\n')
366 douglas 104 {
367 douglas 107 line += byte;
368 douglas 104 }
369     }
370 douglas 107 while (byte != '\n');
371 douglas 104
372 douglas 116 if (debug) cerr << line << "\n";
373    
374 douglas 107 return line;
375 douglas 104 }
376    
377 douglas 107 void IMAPHandler::error(const string& prefix, bool host)
378 douglas 104 {
379 douglas 107 #ifdef _WIN32
380     string error;
381 douglas 104
382 douglas 107 switch (WSAGetLastError())
383 douglas 104 {
384 douglas 107 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 douglas 104
548 douglas 107 cerr << prefix << ": " << error << "\n";
549     #else
550     if (host)
551     {
552     herror(prefix.c_str());
553 douglas 104 }
554 douglas 107 else
555     {
556     perror(prefix.c_str());
557     }
558     #endif // _WIN32
559 douglas 104 }
560    
561 douglas 107 void IMAPHandler::error(const string& prefix, int code)
562 douglas 104 {
563 douglas 107 string error;
564 douglas 104
565 douglas 107 switch (SSL_get_error(ssl, code))
566 douglas 104 {
567 douglas 107 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 douglas 104 {
583 douglas 107 error = ERR_reason_error_string(err);
584 douglas 104 }
585 douglas 107 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 douglas 104 }
608    
609 douglas 107 cerr << prefix << ": " << error << "\n";
610 douglas 104 }