ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/IMAPHandler/IMAPHandler.cpp
Revision: 124
Committed: 2003-04-02T21:13:46-08:00 (19 years, 8 months ago) by douglas
Original Path: trunk/IMAPHandler/IMAPHandler.cpp
File size: 10684 byte(s)
Log Message:
More fixing!

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