ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/IMAPHandler/IMAPHandler.cpp
Revision: 122
Committed: 2003-04-02T15:48:57-08:00 (19 years, 8 months ago) by douglas
File size: 10525 byte(s)
Log Message:
Fixed LF and CRLF stuff!

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 + "\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 + "\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 + "\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 istringstream lines(line);
277
278 while (lines.good())
279 {
280 string line;
281
282 std::getline(lines, line);
283 sprintf(buffer, "%s\r\n", line.c_str());
284
285 if (tls)
286 {
287 if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
288 {
289 error(program + ": SSL Write", code);
290 exit(1);
291 }
292 }
293 else
294 {
295 if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
296 {
297 error(program + ": Send");
298 exit(1);
299 }
300 }
301
302 lines.peek();
303 }
304 }
305
306 string IMAPHandler::getline()
307 {
308 string line;
309 char byte;
310
311 do
312 {
313 if (tls)
314 {
315 if (int code = SSL_read(ssl, &byte, 1) <= 0)
316 {
317 error(program + ": SSL Read", code);
318 exit(1);
319 }
320 }
321 else
322 {
323 if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
324 {
325 error(program + ": Recv");
326 exit(1);
327 }
328 }
329
330 if (byte != '\r' && byte != '\n')
331 {
332 line += byte;
333 }
334 }
335 while (byte != '\n');
336
337 if (debug) cerr << line << "\n";
338
339 return line;
340 }
341
342 void IMAPHandler::error(const string& prefix, bool host)
343 {
344 #ifdef _WIN32
345 string error;
346
347 switch (WSAGetLastError())
348 {
349 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
513 cerr << prefix << ": " << error << "\n";
514 #else
515 if (host)
516 {
517 herror(prefix.c_str());
518 }
519 else
520 {
521 perror(prefix.c_str());
522 }
523 #endif // _WIN32
524 }
525
526 void IMAPHandler::error(const string& prefix, int code)
527 {
528 string error;
529
530 switch (SSL_get_error(ssl, code))
531 {
532 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 {
548 error = ERR_reason_error_string(err);
549 }
550 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 }
573
574 cerr << prefix << ": " << error << "\n";
575 }