ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/IMAPHandler/IMAPHandler.cpp
Revision: 114
Committed: 2003-03-31T23:08:58-08:00 (19 years, 10 months ago) by douglas
Original Path: trunk/IMAPHandler/IMAPHandler.cpp
File size: 10395 byte(s)
Log Message:
More, more!

File Contents

# User Rev Content
1 douglas 108 // IMAP Handler
2     //
3     // Douglas Thrift
4     //
5     // IMAPHandler.cpp
6    
7     #include "IMAPHandler.h"
8    
9     IMAPHandler::IMAPHandler(const string& server, bool tls)
10     {
11 douglas 113 letter = 'a';
12     number = 0;
13    
14 douglas 108 this->tls = tls;
15     buffer = new char[BUFSIZ + 1];
16    
17     #ifdef _WIN32
18     if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
19     {
20     error(program + ": WSAStartup");
21     exit(1);
22     }
23     #endif // _WIN32
24    
25     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    
34     address.sin_family = AF_INET;
35    
36     if ((host = gethostbyname(server.c_str())) == NULL)
37     {
38     error(program + ": Host: " + server, true);
39     exit(1);
40     }
41    
42     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     {
48     error(program + ": Connect");
49     exit(1);
50     }
51    
52     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     {
68     cerr << program << ": SSL CTX New: " <<
69     ERR_reason_error_string(ERR_get_error()) << "\n";
70     exit(1);
71     }
72    
73     ssl = SSL_new(ctx);
74    
75     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     }
81    
82     if (int code = SSL_connect(ssl) <= 0)
83     {
84     error(program + ": SSL Connect", code);
85     exit(1);
86     }
87     }
88    
89 douglas 113 getline();
90 douglas 108 }
91    
92     IMAPHandler::~IMAPHandler()
93     {
94     if (tls)
95     {
96     SSL_shutdown(ssl);
97     SSL_free(ssl);
98     SSL_CTX_free(ctx);
99     }
100    
101     closesocket(sock);
102    
103     delete [] buffer;
104    
105     #ifdef _WIN32
106     WSACleanup();
107     #endif // _WIN32
108     }
109    
110     string IMAPHandler::starttls()
111     {
112     string answer = imap("STARTTLS");
113    
114     if (success)
115     {
116 douglas 113 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 108 }
152    
153     return answer;
154     }
155    
156 douglas 113 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 108 string IMAPHandler::imap(const string& imap)
178     {
179     string result;
180    
181 douglas 113 string sequence = command();
182     putline(sequence + " " + imap);
183    
184     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     result += input + "\r\n";
202     }
203     }
204    
205     return result;
206     }
207    
208     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     result += input + "\r\n";
233     }
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 douglas 114 string sequence = command();
245     putline(sequence + " " + imap + " " + args);
246     putline(message);
247 douglas 108
248 douglas 114 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     result += input + "\r\n";
266     }
267     }
268    
269 douglas 108 return result;
270     }
271    
272     void IMAPHandler::putline(const string line)
273     {
274 douglas 113 if (debug) cerr << line << "\n";
275    
276 douglas 108 sprintf(buffer, "%s\r\n", line.c_str());
277    
278     if (tls)
279     {
280     if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
281     {
282     error(program + ": SSL Write", code);
283     exit(1);
284     }
285     }
286     else
287     {
288     if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
289     {
290     error(program + ": Send");
291     exit(1);
292     }
293     }
294     }
295    
296     string IMAPHandler::getline()
297     {
298     string line;
299     char byte;
300    
301     do
302     {
303     if (tls)
304     {
305     if (int code = SSL_read(ssl, &byte, 1) <= 0)
306     {
307     error(program + ": SSL Read", code);
308     exit(1);
309     }
310     }
311     else
312     {
313     if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
314     {
315     error(program + ": Recv");
316     exit(1);
317     }
318     }
319    
320     if (byte != '\r' && byte != '\n')
321     {
322     line += byte;
323     }
324     }
325     while (byte != '\n');
326    
327 douglas 113 if (debug) cerr << line << "\n";
328    
329 douglas 108 return line;
330     }
331    
332     void IMAPHandler::error(const string& prefix, bool host)
333     {
334     #ifdef _WIN32
335     string error;
336    
337     switch (WSAGetLastError())
338     {
339     case WSAEACCES:
340     error = "Permission denied.";
341     break;
342     case WSAEADDRINUSE:
343     error = "Address already in use.";
344     break;
345     case WSAEADDRNOTAVAIL:
346     error = "Cannot assign requested address.";
347     break;
348     case WSAEAFNOSUPPORT:
349     error = "Address family not supported by protocol family.";
350     break;
351     case WSAEALREADY:
352     error = "Operation already in progress.";
353     break;
354     case WSAECONNABORTED:
355     error = "Software caused connection abort.";
356     break;
357     case WSAECONNREFUSED:
358     error = "Connection refused.";
359     break;
360     case WSAECONNRESET:
361     error = "Connection reset by peer.";
362     break;
363     case WSAEDESTADDRREQ:
364     error = "Destination address required.";
365     break;
366     case WSAEFAULT:
367     error = "Bad address.";
368     break;
369     case WSAEHOSTDOWN:
370     error = "Host is down.";
371     break;
372     case WSAEHOSTUNREACH:
373     error = "No route to host.";
374     break;
375     case WSAEINPROGRESS:
376     error = "Operation now in progress.";
377     break;
378     case WSAEINTR:
379     error = "Interrupted function call.";
380     break;
381     case WSAEINVAL:
382     error = "Invalid argument.";
383     break;
384     case WSAEISCONN:
385     error = "Socket is already connected.";
386     break;
387     case WSAEMFILE:
388     error = "Too many open files.";
389     break;
390     case WSAEMSGSIZE:
391     error = "Message too long.";
392     break;
393     case WSAENETDOWN:
394     error = "Network is down.";
395     break;
396     case WSAENETRESET:
397     error = "Network dropped connection on reset.";
398     break;
399     case WSAENETUNREACH:
400     error = "Network is unreachable.";
401     break;
402     case WSAENOBUFS:
403     error = "No buffer space available.";
404     break;
405     case WSAENOPROTOOPT:
406     error = "Bad protocol option.";
407     break;
408     case WSAENOTCONN:
409     error = "Socket is not connected.";
410     break;
411     case WSAENOTSOCK:
412     error = "Socket operation on non-socket.";
413     break;
414     case WSAEOPNOTSUPP:
415     error = "Operation not supported.";
416     break;
417     case WSAEPFNOSUPPORT:
418     error = "Protocol family not supported.";
419     break;
420     case WSAEPROCLIM:
421     error = "Too many processes.";
422     break;
423     case WSAEPROTONOSUPPORT:
424     error = "Protocol not supported.";
425     break;
426     case WSAEPROTOTYPE:
427     error = "Protocol wrong type for socket.";
428     break;
429     case WSAESHUTDOWN:
430     error = "Cannot send after socket shutdown.";
431     break;
432     case WSAESOCKTNOSUPPORT:
433     error = "Socket type not supported.";
434     break;
435     case WSAETIMEDOUT:
436     error = "Connection timed out.";
437     break;
438     case WSATYPE_NOT_FOUND:
439     error = "Class type not found.";
440     break;
441     case WSAEWOULDBLOCK:
442     error = "Resource temporarily unavailable.";
443     break;
444     case WSAHOST_NOT_FOUND:
445     error = "Host not found.";
446     break;
447     case WSA_INVALID_HANDLE:
448     error = "Specified event object handle is invalid.";
449     break;
450     case WSA_INVALID_PARAMETER:
451     error = "One or more parameters are invalid.";
452     break;
453     // case WSAINVALIDPROCTABLE:
454     // error = "Invalid procedure table from service provider.";
455     // break;
456     // case WSAINVALIDPROVIDER:
457     // error = "Invalid service provider version number.";
458     // break;
459     case WSA_IO_INCOMPLETE:
460     error = "Overlapped I/O event object not in signaled state.";
461     break;
462     case WSA_IO_PENDING:
463     error = "Overlapped operations will complete later.";
464     break;
465     case WSA_NOT_ENOUGH_MEMORY:
466     error = "Insufficient memory available.";
467     break;
468     case WSANOTINITIALISED:
469     error = "Successful WSAStartup not yet performed.";
470     break;
471     case WSANO_DATA:
472     error = "Valid name, no data record of requested type.";
473     break;
474     case WSANO_RECOVERY:
475     error = "This is a non-recoverable error.";
476     break;
477     // case WSAPROVIDERFAILEDINIT:
478     // error = "Unable to initialize a service provider.";
479     // break;
480     case WSASYSCALLFAILURE:
481     error = "System call failure.";
482     break;
483     case WSASYSNOTREADY:
484     error = "Network subsystem is unavailable.";
485     break;
486     case WSATRY_AGAIN:
487     error = "Non-authoritative host not found.";
488     break;
489     case WSAVERNOTSUPPORTED:
490     error = "WINSOCK.DLL version out of range.";
491     break;
492     case WSAEDISCON:
493     error = "Graceful shutdown in progress.";
494     break;
495     case WSA_OPERATION_ABORTED:
496     error = "Overlapped operation aborted.";
497     break;
498     default:
499     error = "Unknown error.";
500     break;
501     }
502    
503     cerr << prefix << ": " << error << "\n";
504     #else
505     if (host)
506     {
507     herror(prefix.c_str());
508     }
509     else
510     {
511     perror(prefix.c_str());
512     }
513     #endif // _WIN32
514     }
515    
516     void IMAPHandler::error(const string& prefix, int code)
517     {
518     string error;
519    
520     switch (SSL_get_error(ssl, code))
521     {
522     case SSL_ERROR_NONE:
523     error = "The TLS/SSL I/O operation completed.";
524     break;
525     case SSL_ERROR_ZERO_RETURN:
526     error = "The TLS/SSL connection has been closed.";
527     break;
528     case SSL_ERROR_WANT_READ:
529     case SSL_ERROR_WANT_WRITE:
530     case SSL_ERROR_WANT_CONNECT:
531     // case SSL_ERROR_WANT_ACCEPT:
532     case SSL_ERROR_WANT_X509_LOOKUP:
533     error = "The operation did not complete.";
534     break;
535     case SSL_ERROR_SYSCALL:
536     if (int err = ERR_get_error() != 0)
537     {
538     error = ERR_reason_error_string(err);
539     }
540     else
541     {
542     switch (code)
543     {
544     case 0:
545     error = "An EOF was observed that violates the protocol.";
546     break;
547     case -1:
548     this->error(prefix);
549     return;
550     default:
551     error = "Unknown error.";
552     break;
553     }
554     }
555     break;
556     case SSL_ERROR_SSL:
557     error = ERR_reason_error_string(ERR_get_error());
558     break;
559     default:
560     error = "Unknown error.";
561     break;
562     }
563    
564     cerr << prefix << ": " << error << "\n";
565     }