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

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 istringstream lines(line);
275
276 while (lines.good())
277 {
278 string line;
279
280 std::getline(lines, line);
281 if (debug) cerr << line << "\n";
282
283 sprintf(buffer, "%s\r\n", line.c_str());
284
285 // for (unsigned index = 0; index < strlen(buffer); index++)
286 // {
287 // cout << "\"" << buffer[index] << "\" = " << int(buffer[index])
288 // << "\n";
289 // }
290
291 if (tls)
292 {
293 if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
294 {
295 error(program + ": SSL Write", code);
296 exit(1);
297 }
298 }
299 else
300 {
301 if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
302 {
303 error(program + ": Send");
304 exit(1);
305 }
306 }
307
308 lines.peek();
309 }
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 if (debug) cerr << line << "\n";
344
345 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 }