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

File Contents

# Content
1 // 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 letter = 'a';
12 number = 0;
13
14 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 getline();
90 }
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 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 }
152
153 return answer;
154 }
155
156 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 string IMAPHandler::imap(const string& imap)
178 {
179 string result;
180
181 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 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 result += input + "\r\n";
266 }
267 }
268
269 return result;
270 }
271
272 void IMAPHandler::putline(const string line)
273 {
274 if (debug) cerr << line << "\n";
275
276 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 if (debug) cerr << line << "\n";
328
329 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 }