ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/proj/trunk/WinXPFAQPoll/IMAPHandler.cpp
(Generate patch)

Comparing trunk/WinXPFAQPoll/IMAPHandler.cpp (file contents):
Revision 104 by douglas, 2003-03-31T20:18:26-08:00 vs.
Revision 116 by douglas, 2003-04-01T00:43:13-08:00

# Line 51 | Line 51
51  
52   #include "IMAPHandler.h"
53  
54 + IMAPHandler::IMAPHandler(const string& server, bool tls)
55 + {
56 +        letter = 'a';
57 +        number = 0;
58 +
59 +        this->tls = tls;
60 +        buffer = new char[BUFSIZ + 1];
61 +
62   #ifdef _WIN32
63 < #define PATH_SEPARATOR "\\"
64 < #define ENV_SEPARATOR ';'
65 < #else
66 < #define PATH_SEPARATOR "/"
67 < #define ENV_SEPARATOR ':'
68 < #endif
63 >        if (WSAStartup(MAKEWORD(2, 0), &data) != 0)
64 >        {
65 >                error(program + ": WSAStartup");
66 >                exit(1);
67 >        }
68 > #endif // _WIN32
69  
70 < IMAPHandler::IMAPHandler(const string& host, unsigned port)
71 < {
72 <        setJarPath();
70 >        if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
71 >        {
72 >                error(program + ": Socket");
73 >                exit(1);
74 >        }
75 >        
76 >        sockaddr_in address;
77 >        hostent* host;
78  
79 <        options[0].optionString = jarPath;
67 <        memset(&vm_args, 0, sizeof (vm_args));
68 <        vm_args.version = JNI_VERSION_1_2;
69 <        vm_args.nOptions = 1;
70 <        vm_args.options = options;
79 >        address.sin_family = AF_INET;
80  
81 <        status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
81 >        if ((host = gethostbyname(server.c_str())) == NULL)
82 >        {
83 >                error(program + ": Host: " + server, true);
84 >                exit(1);
85 >        }
86 >
87 >        address.sin_addr = *((in_addr*)*host->h_addr_list);
88 >        address.sin_port = htons(tls ? 993 : 143);
89  
90 <        if (status != JNI_ERR)
90 >        if (connect(sock, (sockaddr*)&address, sizeof(sockaddr_in)) ==
91 >                SOCKET_ERROR)
92          {
93 <                cls = env->FindClass("IMAPHandler");
93 >                error(program + ": Connect");
94 >                exit(1);
95 >        }
96 >
97 >        if (tls)
98 >        {
99 >                SSL_load_error_strings();
100 >                SSL_library_init();
101 >
102 >                char* seed = new char[BUFSIZ + 1];
103 >                time_t moment = time(NULL);
104 >                sprintf(seed, "froofy%sfoofoo", ctime(&moment));
105 >
106 >                RAND_add(seed, strlen(seed), 0.007456);
107 >
108 >                delete [] seed;
109  
110 <                if (cls != 0)
110 >                ctx = SSL_CTX_new(TLSv1_client_method());
111 >                if (ctx == NULL)
112                  {
113 <                        mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;IZ)V");
113 >                        cerr << program << ": SSL CTX New: " <<
114 >                                ERR_reason_error_string(ERR_get_error()) << "\n";
115 >                        exit(1);
116 >                }
117  
118 <                        if (mid != 0)
83 <                        {
84 <                                jstring hostJ = env->NewStringUTF(host.c_str());
85 <                                jint portJ = port;
86 < #ifdef _DEBUG
87 <                                jboolean debugJ = debug;
88 < #else
89 <                                jboolean debugJ = false;
90 < #endif
118 >                ssl = SSL_new(ctx);
119  
120 <                                obj = env->NewObject(cls, mid, hostJ, portJ, debugJ);
121 <                        }
120 >                if (SSL_set_fd(ssl, sock) == 0)
121 >                {
122 >                        cerr << program << ": SSL Set FD: " <<
123 >                                ERR_reason_error_string(ERR_get_error()) << "\n";
124 >                        exit(1);
125 >                }
126 >
127 >                if (int code = SSL_connect(ssl) <= 0)
128 >                {
129 >                        error(program + ": SSL Connect", code);
130 >                        exit(1);
131                  }
132          }
133 +
134 +        getline();
135   }
136  
137   IMAPHandler::~IMAPHandler()
138   {
139 <        if (status != JNI_ERR)
139 >        if (tls)
140          {
141 <                jvm->DestroyJavaVM();
141 >                SSL_shutdown(ssl);
142 >                SSL_free(ssl);
143 >                SSL_CTX_free(ctx);
144          }
145 +
146 +        closesocket(sock);
147 +        
148 +        delete [] buffer;
149 +
150 + #ifdef _WIN32
151 +        WSACleanup();
152 + #endif // _WIN32
153   }
154  
155 < bool IMAPHandler::successful()
155 > string IMAPHandler::starttls()
156   {
157 <        bool answer;
157 >        string answer = imap("STARTTLS");
158  
159 <        if (cls != 0)
159 >        if (success)
160          {
161 <                mid = env->GetMethodID(cls, "successful", "()Z");
161 >                tls = true;
162 >
163 >                SSL_load_error_strings();
164 >                SSL_library_init();
165 >
166 >                char* seed = new char[BUFSIZ + 1];
167 >                time_t moment = time(NULL);
168 >                sprintf(seed, "froofy%sfoofoo", ctime(&moment));
169  
170 <                if (mid != 0)
170 >                RAND_add(seed, strlen(seed), 0.007456);
171 >
172 >                delete [] seed;
173 >
174 >                ctx = SSL_CTX_new(TLSv1_client_method());
175 >                if (ctx == NULL)
176                  {
177 <                        jboolean answerJ = env->CallBooleanMethod(obj, mid);
177 >                        cerr << program << ": SSL CTX New: " <<
178 >                                ERR_reason_error_string(ERR_get_error()) << "\n";
179 >                        exit(1);
180 >                }
181 >
182 >                ssl = SSL_new(ctx);
183  
184 <                        answer = answerJ != 0;
184 >                if (SSL_set_fd(ssl, sock) == 0)
185 >                {
186 >                        cerr << program << ": SSL Set FD: " <<
187 >                                ERR_reason_error_string(ERR_get_error()) << "\n";
188 >                        exit(1);
189 >                }
190 >
191 >                if (int code = SSL_connect(ssl) <= 0)
192 >                {
193 >                        error(program + ": SSL Connect", code);
194 >                        exit(1);
195                  }
196          }
197  
198          return answer;
199   }
200  
201 < void IMAPHandler::setJarPath()
201 > string IMAPHandler::command()
202   {
203 <        const string jarFile = "IMAPHandler.jar";
204 <        string jarFilePath = jarFile;
203 >        char buffer[4];
204 >        sprintf(buffer, "%03u", number++);
205 >
206 >        string sequence = letter + string(buffer);
207  
208 <        ifstream fin(jarFilePath.c_str());
131 <        if (!fin.is_open())
208 >        if (number > 999)
209          {
210 <                unsigned end = program.rfind(PATH_SEPARATOR);
211 <                if (end != string::npos)
212 <                {
213 <                        string path = program.substr(0, end);
210 >                letter++;
211 >                number = 0;
212 >        }
213 >
214 >        if (letter > 'z')
215 >        {
216 >                letter = 'a';
217 >        }
218  
219 <                        jarFilePath = path + PATH_SEPARATOR + jarFile;
219 >        return sequence;
220 > }
221  
222 <                        fin.open(jarFilePath.c_str());
223 <                        if (!fin.is_open())
224 <                        {
225 <                                cerr << program << ": Could not find required file: "
226 <                                        << jarFile << "\n";
227 <                                exit(1);
228 <                        }
229 <                        else
230 <                        {
231 <                                fin.close();
232 <                        }
222 > string IMAPHandler::imap(const string& imap)
223 > {
224 >        string result;
225 >
226 >        string sequence = command();
227 >        putline(sequence + " " + imap);
228 >
229 >        while (true)
230 >        {
231 >                string input = getline();
232 >
233 >                if (input.find(sequence + " OK") == 0)
234 >                {
235 >                        success = true;
236 >                        break;
237 >                }
238 >                else if (input.find(sequence + " NO") == 0 || input.find(sequence +
239 >                        " BAD") == 0)
240 >                {
241 >                        success = false;
242 >                        break;
243                  }
244                  else
245                  {
246 <                        string envPath = getenv("PATH");
247 <
248 <                        if (debug) cerr << "envPath = " << envPath << "\n";
157 <
158 <                        unsigned begin = 0;
159 <                        do
160 <                        {
161 <                                unsigned end = envPath.find(ENV_SEPARATOR, begin);
162 <                                string path = envPath.substr(begin, end);
246 >                        result += input + "\r\n";
247 >                }
248 >        }
249  
250 <                                if (debug) cerr << "path = " << path << "\n";
250 >        return result;
251 > }
252  
253 <                                jarFilePath = path + PATH_SEPARATOR + jarFile;
253 > string IMAPHandler::imap(const string& imap, const string& args)
254 > {
255 >        string result;
256  
257 <                                fin.open(jarFilePath.c_str());
258 <                                if (fin.is_open())
170 <                                {
171 <                                        fin.close();
172 <                                        break;
173 <                                }
257 >        string sequence = command();
258 >        putline(sequence + " " + imap + " " + args);
259  
260 <                                begin = end != string::npos ? end + 1 : string::npos;
261 <                        }
262 <                        while (begin < envPath.length());
260 >        while (true)
261 >        {
262 >                string input = getline();
263  
264 <                        if (begin == string::npos)
265 <                        {
266 <                                cerr << program << ": Could not find required file: "
267 <                                        << jarFile << "\n";
268 <                                exit(1);
269 <                        }
264 >                if (input.find(sequence + " OK") == 0)
265 >                {
266 >                        success = true;
267 >                        break;
268 >                }
269 >                else if (input.find(sequence + " NO") == 0 || input.find(sequence +
270 >                        " BAD") == 0)
271 >                {
272 >                        success = false;
273 >                        break;
274 >                }
275 >                else
276 >                {
277 >                        result += input + "\r\n";
278                  }
279          }
187        else
188        {
189                fin.close();
190        }
191
192        string jarPath = "-Djava.class.path=" + jarFilePath;
280  
281 <        this->jarPath = new char[jarPath.length()];
195 <        strcpy(this->jarPath, jarPath.c_str());
281 >        return result;
282   }
283  
284 < string IMAPHandler::imap(char* imap)
284 > string IMAPHandler::imap(const string& imap, const string& args, const string&
285 >        message)
286   {
287          string result;
288  
289 <        if (cls != 0)
289 >        string sequence = command();
290 >        putline(sequence + " " + imap + " " + args);
291 >        putline(message);
292 >
293 >        while (true)
294          {
295 <                mid = env->GetMethodID(cls, imap, "()Ljava/lang/String;");
295 >                string input = getline();
296  
297 <                if (mid != 0)
297 >                if (input.find(sequence + " OK") == 0)
298                  {
299 <                        jstring resultJ = (jstring)env->CallObjectMethod(obj, mid);
300 <
301 <                        const char* resultC = env->GetStringUTFChars(resultJ, 0);
302 <                        result = resultC;
303 <                        env->ReleaseStringUTFChars(resultJ, resultC);
299 >                        success = true;
300 >                        break;
301 >                }
302 >                else if (input.find(sequence + " NO") == 0 || input.find(sequence +
303 >                        " BAD") == 0)
304 >                {
305 >                        success = false;
306 >                        break;
307 >                }
308 >                else
309 >                {
310 >                        result += input + "\r\n";
311                  }
312          }
313  
314          return result;
315   }
316  
317 < string IMAPHandler::imap(char* imap, const string& args)
317 > void IMAPHandler::putline(const string line)
318   {
319 <        string result;
319 >        if (debug) cerr << line << "\n";
320  
321 <        if (cls != 0)
224 <        {
225 <                mid = env->GetMethodID(cls, imap,
226 <                        "(Ljava/lang/String;)Ljava/lang/String;");
321 >        sprintf(buffer, "%s\r\n", line.c_str());
322  
323 <                if (mid != 0)
323 >        if (tls)
324 >        {
325 >                if (int code = SSL_write(ssl, buffer, strlen(buffer)) <= 0)
326                  {
327 <                        jstring argsJ = env->NewStringUTF(args.c_str());
327 >                        error(program + ": SSL Write", code);
328 >                        exit(1);
329 >                }
330 >        }
331 >        else
332 >        {
333 >                if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR)
334 >                {
335 >                        error(program + ": Send");
336 >                        exit(1);
337 >                }
338 >        }
339 > }
340 >
341 > string IMAPHandler::getline()
342 > {
343 >        string line;
344 >        char byte;
345  
346 <                        jstring resultJ = (jstring)env->CallObjectMethod(obj, mid, argsJ);
346 >        do
347 >        {
348 >                if (tls)
349 >                {
350 >                        if (int code = SSL_read(ssl, &byte, 1) <= 0)
351 >                        {
352 >                                error(program + ": SSL Read", code);
353 >                                exit(1);
354 >                        }
355 >                }
356 >                else
357 >                {
358 >                        if (recv(sock, &byte, 1, 0) == SOCKET_ERROR)
359 >                        {
360 >                                error(program + ": Recv");
361 >                                exit(1);
362 >                        }
363 >                }
364  
365 <                        const char* resultC = env->GetStringUTFChars(resultJ, 0);
366 <                        result = resultC;
367 <                        env->ReleaseStringUTFChars(resultJ, resultC);
365 >                if (byte != '\r' && byte != '\n')
366 >                {
367 >                        line += byte;
368                  }
369          }
370 +        while (byte != '\n');
371  
372 <        return result;
372 >        if (debug) cerr << line << "\n";
373 >
374 >        return line;
375   }
376  
377 < string IMAPHandler::imap(char* imap, const string& args, const string& message)
377 > void IMAPHandler::error(const string& prefix, bool host)
378   {
379 <        string result;
379 > #ifdef _WIN32
380 >        string error;
381  
382 <        if (cls != 0)
382 >        switch (WSAGetLastError())
383          {
384 <                mid = env->GetMethodID(cls, imap,
385 <                        "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
384 >        case WSAEACCES:
385 >                error = "Permission denied.";
386 >                break;
387 >        case WSAEADDRINUSE:
388 >                error = "Address already in use.";
389 >                break;
390 >        case WSAEADDRNOTAVAIL:
391 >                error = "Cannot assign requested address.";
392 >                break;
393 >        case WSAEAFNOSUPPORT:
394 >                error = "Address family not supported by protocol family.";
395 >                break;
396 >        case WSAEALREADY:
397 >                error = "Operation already in progress.";
398 >                break;
399 >        case WSAECONNABORTED:
400 >                error = "Software caused connection abort.";
401 >                break;
402 >        case WSAECONNREFUSED:
403 >                error = "Connection refused.";
404 >                break;
405 >        case WSAECONNRESET:
406 >                error = "Connection reset by peer.";
407 >                break;
408 >        case WSAEDESTADDRREQ:
409 >                error = "Destination address required.";
410 >                break;
411 >        case WSAEFAULT:
412 >                error = "Bad address.";
413 >                break;
414 >        case WSAEHOSTDOWN:
415 >                error = "Host is down.";
416 >                break;
417 >        case WSAEHOSTUNREACH:
418 >                error = "No route to host.";
419 >                break;
420 >        case WSAEINPROGRESS:
421 >                error = "Operation now in progress.";
422 >                break;
423 >        case WSAEINTR:
424 >                error = "Interrupted function call.";
425 >                break;
426 >        case WSAEINVAL:
427 >                error = "Invalid argument.";
428 >                break;
429 >        case WSAEISCONN:
430 >                error = "Socket is already connected.";
431 >                break;
432 >        case WSAEMFILE:
433 >                error = "Too many open files.";
434 >                break;
435 >        case WSAEMSGSIZE:
436 >                error = "Message too long.";
437 >                break;
438 >        case WSAENETDOWN:
439 >                error = "Network is down.";
440 >                break;
441 >        case WSAENETRESET:
442 >                error = "Network dropped connection on reset.";
443 >                break;
444 >        case WSAENETUNREACH:
445 >                error = "Network is unreachable.";
446 >                break;
447 >        case WSAENOBUFS:
448 >                error = "No buffer space available.";
449 >                break;
450 >        case WSAENOPROTOOPT:
451 >                error = "Bad protocol option.";
452 >                break;
453 >        case WSAENOTCONN:
454 >                error = "Socket is not connected.";
455 >                break;
456 >        case WSAENOTSOCK:
457 >                error = "Socket operation on non-socket.";
458 >                break;
459 >        case WSAEOPNOTSUPP:
460 >                error = "Operation not supported.";
461 >                break;
462 >        case WSAEPFNOSUPPORT:
463 >                error = "Protocol family not supported.";
464 >                break;
465 >        case WSAEPROCLIM:
466 >                error = "Too many processes.";
467 >                break;
468 >        case WSAEPROTONOSUPPORT:
469 >                error = "Protocol not supported.";
470 >                break;
471 >        case WSAEPROTOTYPE:
472 >                error = "Protocol wrong type for socket.";
473 >                break;
474 >        case WSAESHUTDOWN:
475 >                error = "Cannot send after socket shutdown.";
476 >                break;
477 >        case WSAESOCKTNOSUPPORT:
478 >                error = "Socket type not supported.";
479 >                break;
480 >        case WSAETIMEDOUT:
481 >                error = "Connection timed out.";
482 >                break;
483 >        case WSATYPE_NOT_FOUND:
484 >                error = "Class type not found.";
485 >                break;
486 >        case WSAEWOULDBLOCK:
487 >                error = "Resource temporarily unavailable.";
488 >                break;
489 >        case WSAHOST_NOT_FOUND:
490 >                error = "Host not found.";
491 >                break;
492 >        case WSA_INVALID_HANDLE:
493 >                error = "Specified event object handle is invalid.";
494 >                break;
495 >        case WSA_INVALID_PARAMETER:
496 >                error = "One or more parameters are invalid.";
497 >                break;
498 > //      case WSAINVALIDPROCTABLE:
499 > //              error = "Invalid procedure table from service provider.";
500 > //              break;
501 > //      case WSAINVALIDPROVIDER:
502 > //              error = "Invalid service provider version number.";
503 > //              break;
504 >        case WSA_IO_INCOMPLETE:
505 >                error = "Overlapped I/O event object not in signaled state.";
506 >                break;
507 >        case WSA_IO_PENDING:
508 >                error = "Overlapped operations will complete later.";
509 >                break;
510 >        case WSA_NOT_ENOUGH_MEMORY:
511 >                error = "Insufficient memory available.";
512 >                break;
513 >        case WSANOTINITIALISED:
514 >                error = "Successful WSAStartup not yet performed.";
515 >                break;
516 >        case WSANO_DATA:
517 >                error = "Valid name, no data record of requested type.";
518 >                break;
519 >        case WSANO_RECOVERY:
520 >                error = "This is a non-recoverable error.";
521 >                break;
522 > //      case WSAPROVIDERFAILEDINIT:
523 > //              error = "Unable to initialize a service provider.";
524 > //              break;
525 >        case WSASYSCALLFAILURE:
526 >                error = "System call failure.";
527 >                break;
528 >        case WSASYSNOTREADY:
529 >                error = "Network subsystem is unavailable.";
530 >                break;
531 >        case WSATRY_AGAIN:
532 >                error = "Non-authoritative host not found.";
533 >                break;
534 >        case WSAVERNOTSUPPORTED:
535 >                error = "WINSOCK.DLL version out of range.";
536 >                break;
537 >        case WSAEDISCON:
538 >                error = "Graceful shutdown in progress.";
539 >                break;
540 >        case WSA_OPERATION_ABORTED:
541 >                error = "Overlapped operation aborted.";
542 >                break;
543 >        default:
544 >                error = "Unknown error.";
545 >                break;
546 >        }
547  
548 <                if (mid != 0)
549 <                {
550 <                        jstring argsJ = env->NewStringUTF(args.c_str());
551 <                        jstring messageJ = env->NewStringUTF(message.c_str());
548 >        cerr << prefix << ": " << error << "\n";
549 > #else
550 >        if (host)
551 >        {
552 >                herror(prefix.c_str());
553 >        }
554 >        else
555 >        {
556 >                perror(prefix.c_str());
557 >        }
558 > #endif // _WIN32
559 > }
560  
561 <                        jstring resultJ = (jstring)env->CallObjectMethod(obj, mid, argsJ,
562 <                                messageJ);
561 > void IMAPHandler::error(const string& prefix, int code)
562 > {
563 >        string error;
564  
565 <                        const char* resultC = env->GetStringUTFChars(resultJ, 0);
566 <                        result = resultC;
567 <                        env->ReleaseStringUTFChars(resultJ, resultC);
565 >        switch (SSL_get_error(ssl, code))
566 >        {
567 >        case SSL_ERROR_NONE:
568 >                error = "The TLS/SSL I/O operation completed.";
569 >                break;
570 >        case SSL_ERROR_ZERO_RETURN:
571 >                error = "The TLS/SSL connection has been closed.";
572 >                break;
573 >        case SSL_ERROR_WANT_READ:
574 >        case SSL_ERROR_WANT_WRITE:
575 >        case SSL_ERROR_WANT_CONNECT:
576 > //      case SSL_ERROR_WANT_ACCEPT:
577 >        case SSL_ERROR_WANT_X509_LOOKUP:
578 >                error = "The operation did not complete.";
579 >                break;
580 >        case SSL_ERROR_SYSCALL:
581 >                if (int err = ERR_get_error() != 0)
582 >                {
583 >                        error = ERR_reason_error_string(err);
584 >                }
585 >                else
586 >                {
587 >                        switch (code)
588 >                        {
589 >                        case 0:
590 >                                error = "An EOF was observed that violates the protocol.";
591 >                                break;
592 >                        case -1:
593 >                                this->error(prefix);
594 >                                return;
595 >                        default:
596 >                                error = "Unknown error.";
597 >                                break;
598 >                        }
599                  }
600 +                break;
601 +        case SSL_ERROR_SSL:
602 +                error = ERR_reason_error_string(ERR_get_error());
603 +                break;
604 +        default:
605 +                error = "Unknown error.";
606 +                break;
607          }
608  
609 <        return result;
609 >        cerr << prefix << ": " << error << "\n";
610   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines