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

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 //
245
246 return result;
247 }
248
249 void IMAPHandler::putline(const string line)
250 {
251 if (debug) cerr << line << "\n";
252
253 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 if (debug) cerr << line << "\n";
305
306 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 }