ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/IMAPHandler/IMAPHandler.cpp
Revision: 113
Committed: 2003-03-31T22:44:44-08:00 (22 years, 2 months ago) by douglas
Original Path: trunk/IMAPHandler/IMAPHandler.cpp
File size: 10007 byte(s)
Log Message:
Ooh, it's working a little better now!

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 108 //
245    
246     return result;
247     }
248    
249     void IMAPHandler::putline(const string line)
250     {
251 douglas 113 if (debug) cerr << line << "\n";
252    
253 douglas 108 sprintf(buffer, "%s\r\n", line.c_str());
254    
255     if (tls)
256     {
257     if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
258     {
259     error(program + ": SSL Write", code);
260     exit(1);
261     }
262     }
263     else
264     {
265     if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
266     {
267     error(program + ": Send");
268     exit(1);
269     }
270     }
271     }
272    
273     string IMAPHandler::getline()
274     {
275     string line;
276     char byte;
277    
278     do
279     {
280     if (tls)
281     {
282     if (int code = SSL_read(ssl, &byte, 1) <= 0)
283     {
284     error(program + ": SSL Read", code);
285     exit(1);
286     }
287     }
288     else
289     {
290     if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
291     {
292     error(program + ": Recv");
293     exit(1);
294     }
295     }
296    
297     if (byte != '\r' && byte != '\n')
298     {
299     line += byte;
300     }
301     }
302     while (byte != '\n');
303    
304 douglas 113 if (debug) cerr << line << "\n";
305    
306 douglas 108 return line;
307     }
308    
309     void IMAPHandler::error(const string& prefix, bool host)
310     {
311     #ifdef _WIN32
312     string error;
313    
314     switch (WSAGetLastError())
315     {
316     case WSAEACCES:
317     error = "Permission denied.";
318     break;
319     case WSAEADDRINUSE:
320     error = "Address already in use.";
321     break;
322     case WSAEADDRNOTAVAIL:
323     error = "Cannot assign requested address.";
324     break;
325     case WSAEAFNOSUPPORT:
326     error = "Address family not supported by protocol family.";
327     break;
328     case WSAEALREADY:
329     error = "Operation already in progress.";
330     break;
331     case WSAECONNABORTED:
332     error = "Software caused connection abort.";
333     break;
334     case WSAECONNREFUSED:
335     error = "Connection refused.";
336     break;
337     case WSAECONNRESET:
338     error = "Connection reset by peer.";
339     break;
340     case WSAEDESTADDRREQ:
341     error = "Destination address required.";
342     break;
343     case WSAEFAULT:
344     error = "Bad address.";
345     break;
346     case WSAEHOSTDOWN:
347     error = "Host is down.";
348     break;
349     case WSAEHOSTUNREACH:
350     error = "No route to host.";
351     break;
352     case WSAEINPROGRESS:
353     error = "Operation now in progress.";
354     break;
355     case WSAEINTR:
356     error = "Interrupted function call.";
357     break;
358     case WSAEINVAL:
359     error = "Invalid argument.";
360     break;
361     case WSAEISCONN:
362     error = "Socket is already connected.";
363     break;
364     case WSAEMFILE:
365     error = "Too many open files.";
366     break;
367     case WSAEMSGSIZE:
368     error = "Message too long.";
369     break;
370     case WSAENETDOWN:
371     error = "Network is down.";
372     break;
373     case WSAENETRESET:
374     error = "Network dropped connection on reset.";
375     break;
376     case WSAENETUNREACH:
377     error = "Network is unreachable.";
378     break;
379     case WSAENOBUFS:
380     error = "No buffer space available.";
381     break;
382     case WSAENOPROTOOPT:
383     error = "Bad protocol option.";
384     break;
385     case WSAENOTCONN:
386     error = "Socket is not connected.";
387     break;
388     case WSAENOTSOCK:
389     error = "Socket operation on non-socket.";
390     break;
391     case WSAEOPNOTSUPP:
392     error = "Operation not supported.";
393     break;
394     case WSAEPFNOSUPPORT:
395     error = "Protocol family not supported.";
396     break;
397     case WSAEPROCLIM:
398     error = "Too many processes.";
399     break;
400     case WSAEPROTONOSUPPORT:
401     error = "Protocol not supported.";
402     break;
403     case WSAEPROTOTYPE:
404     error = "Protocol wrong type for socket.";
405     break;
406     case WSAESHUTDOWN:
407     error = "Cannot send after socket shutdown.";
408     break;
409     case WSAESOCKTNOSUPPORT:
410     error = "Socket type not supported.";
411     break;
412     case WSAETIMEDOUT:
413     error = "Connection timed out.";
414     break;
415     case WSATYPE_NOT_FOUND:
416     error = "Class type not found.";
417     break;
418     case WSAEWOULDBLOCK:
419     error = "Resource temporarily unavailable.";
420     break;
421     case WSAHOST_NOT_FOUND:
422     error = "Host not found.";
423     break;
424     case WSA_INVALID_HANDLE:
425     error = "Specified event object handle is invalid.";
426     break;
427     case WSA_INVALID_PARAMETER:
428     error = "One or more parameters are invalid.";
429     break;
430     // case WSAINVALIDPROCTABLE:
431     // error = "Invalid procedure table from service provider.";
432     // break;
433     // case WSAINVALIDPROVIDER:
434     // error = "Invalid service provider version number.";
435     // break;
436     case WSA_IO_INCOMPLETE:
437     error = "Overlapped I/O event object not in signaled state.";
438     break;
439     case WSA_IO_PENDING:
440     error = "Overlapped operations will complete later.";
441     break;
442     case WSA_NOT_ENOUGH_MEMORY:
443     error = "Insufficient memory available.";
444     break;
445     case WSANOTINITIALISED:
446     error = "Successful WSAStartup not yet performed.";
447     break;
448     case WSANO_DATA:
449     error = "Valid name, no data record of requested type.";
450     break;
451     case WSANO_RECOVERY:
452     error = "This is a non-recoverable error.";
453     break;
454     // case WSAPROVIDERFAILEDINIT:
455     // error = "Unable to initialize a service provider.";
456     // break;
457     case WSASYSCALLFAILURE:
458     error = "System call failure.";
459     break;
460     case WSASYSNOTREADY:
461     error = "Network subsystem is unavailable.";
462     break;
463     case WSATRY_AGAIN:
464     error = "Non-authoritative host not found.";
465     break;
466     case WSAVERNOTSUPPORTED:
467     error = "WINSOCK.DLL version out of range.";
468     break;
469     case WSAEDISCON:
470     error = "Graceful shutdown in progress.";
471     break;
472     case WSA_OPERATION_ABORTED:
473     error = "Overlapped operation aborted.";
474     break;
475     default:
476     error = "Unknown error.";
477     break;
478     }
479    
480     cerr << prefix << ": " << error << "\n";
481     #else
482     if (host)
483     {
484     herror(prefix.c_str());
485     }
486     else
487     {
488     perror(prefix.c_str());
489     }
490     #endif // _WIN32
491     }
492    
493     void IMAPHandler::error(const string& prefix, int code)
494     {
495     string error;
496    
497     switch (SSL_get_error(ssl, code))
498     {
499     case SSL_ERROR_NONE:
500     error = "The TLS/SSL I/O operation completed.";
501     break;
502     case SSL_ERROR_ZERO_RETURN:
503     error = "The TLS/SSL connection has been closed.";
504     break;
505     case SSL_ERROR_WANT_READ:
506     case SSL_ERROR_WANT_WRITE:
507     case SSL_ERROR_WANT_CONNECT:
508     // case SSL_ERROR_WANT_ACCEPT:
509     case SSL_ERROR_WANT_X509_LOOKUP:
510     error = "The operation did not complete.";
511     break;
512     case SSL_ERROR_SYSCALL:
513     if (int err = ERR_get_error() != 0)
514     {
515     error = ERR_reason_error_string(err);
516     }
517     else
518     {
519     switch (code)
520     {
521     case 0:
522     error = "An EOF was observed that violates the protocol.";
523     break;
524     case -1:
525     this->error(prefix);
526     return;
527     default:
528     error = "Unknown error.";
529     break;
530     }
531     }
532     break;
533     case SSL_ERROR_SSL:
534     error = ERR_reason_error_string(ERR_get_error());
535     break;
536     default:
537     error = "Unknown error.";
538     break;
539     }
540    
541     cerr << prefix << ": " << error << "\n";
542     }