ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/IMAPHandler.cpp
Revision: 123
Committed: 2003-04-02T18:10:51-08:00 (22 years, 2 months ago) by douglas
File size: 10525 byte(s)
Log Message:
Got voting stuff working, needed to make some changes to IMAPHandler.

File Contents

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