⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imapserverc.c

📁 linux下的E_MAIL客户端源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  $Id: ImapServerC.C,v 1.38 2001/07/22 18:07:30 evgeny Exp $ *   *  Copyright (c) 1994 HAL Computer Systems International, Ltd. *  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. *                  1315 Dell Avenue *                  Campbell, CA  95008 * * Author: Greg Hilton * Contributors: Tom Lang, Frank Bieser, and others * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * http://www.gnu.org/copyleft/gpl.html * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <config.h>#include "IshAppC.h"#include "MainWinC.h"#include "Misc.h"#include "FolderPrefC.h"#include "ImapServerC.h"#include "ImapFolderC.h"#include "MsgStatus.h"#include "LoginWinC.h"#include "Query.h"#include "Base64.h"#include <hgl/HalAppC.h>#include <hgl/StringC.h>#include <hgl/SysErr.h>#include <hgl/PtrListC.h>#include <hgl/StringListC.h>#include <hgl/CharC.h>#include <hgl/WArgList.h>#include <hgl/WXmString.h>#include <hgl/IntListC.h>#include <Xm/MessageB.h>#include <Xm/Protocols.h>#include <Xm/AtomMgr.h>#include <X11/Intrinsic.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#include <unistd.h>#include <errno.h>#include <string.h>#ifdef HAVE_SYS_SELECT_H# include <sys/select.h>#endif#include <netdb.h>#ifdef HAVE_OPENSSL  // A hack to find out OPENSSLDIR# define HEADER_CRYPTLIB_H#  include <openssl/opensslconf.h># undef HEADER_CRYPTLIB_H# ifndef OPENSSLDIR#  define OPENSSLDIR "/usr/local/ssl"# endif# include <openssl/hmac.h>#endifextern int	debuglev;static PtrListC	*serverList = NULL;#ifdef HAVE_OPENSSLstatic Boolean sslInited = False;#endif/*------------------------------------------------------------------------ * Constructor to open a connection to an imap server */ImapServerC::ImapServerC(const char *hostname, const char *username,    long portnum, Boolean imaps_flag){   sock          = 0;   connected     = False;   TLSEnabled    = False;   authenticated = False;   bugs          = 0L;		// let's assume the implementation is perfect   haveStartTLS  = False;   dataPending   = False;	// Should be no data pending at this point//// save hostname, port # etc in server object//   name = hostname;   port = portnum;   if ( username ) {      user = username;   } else {      user = ishApp->userId;   }//// Init buffers//   lineList = new StringListC;   lineList->AllowDuplicates(TRUE);   lastBuf[0] = 0;   #ifndef HAVE_OPENSSL   if ( imaps_flag ) {      char *errmsg = "Support for secure connections is not compiled in";      halApp->PopupMessage(errmsg);      return;   }#else   imaps = imaps_flag;#endif   if ( !EstablishSession() ) return;//// Add this server to the list//   if ( !serverList ) serverList = new PtrListC;   void	*tmp = (void*)this;   serverList->add(tmp);} // End constructor/*------------------------------------------------------------------------ * Destructor */ImapServerC::~ImapServerC(){   if ( connected ) {      StringListC	output;      Logout(output);   }   delete lineList;//// Remove this server from the list//   if ( serverList ) {      void	*tmp = (void*)this;      serverList->remove(tmp);   }   } // End destructor/*------------------------------------------------------------------------ * Method to establish an authenticated session with the IMAP server * - this is called from the constructor, and also to re-connect if *   the connection drops for some reason. */BooleanImapServerC::EstablishSession(){//// Connect to the server//   connected = Connect();   if ( !connected ) return False;//// Determine capabilities of the server//   if ( !Capability() ) {      CloseSocket();      return False;   }   #ifdef HAVE_OPENSSL   if ( !imaps && haveStartTLS && !(bugs & IMAP_BUG_STARTTLS_BROKEN) ) {      // We MUST re-check capabilities once switched to TLS      if ( StartTLS() && Capability() ) {         ; // OK      } else {         StringC errmsg =            "Can't start TLS; falling back to unencrypted session";         halApp->PopupMessage(errmsg);         // Re-try connecting, this time without TLS         return EstablishSession();      }   }#endif//// Log in if needed//   authenticated = DoLogin();   if ( !authenticated ) {      CloseSocket();      return False;   }      return True;}/*------------------------------------------------------------------------ * Method to connect a socket to the named IMAP server */BooleanImapServerC::Connect(){   StringC	errmsg;   authenticated = False;   dataPending = False;		// Should be no data pending at this point   CloseSocket();//// Get host name//   host = gethostbyname(name);   if ( !host ) {      int	err = errno;      errmsg = "Could not find entry for host: ";      errmsg += name;      errmsg += ".\n" + SystemErrorMessage(err);      halApp->PopupMessage(errmsg);      return False;   }//// Create socket//   sock = socket(AF_INET, SOCK_STREAM, 0);   if ( sock <= 0 ) {      int	err = errno;      errmsg = "Could not create socket.\n";      errmsg += SystemErrorMessage(err);      halApp->PopupMessage(errmsg);      return False;   }//// Open connection//   struct sockaddr_in	sin;   memset((char*)&sin, 0, sizeof(sin));   sin.sin_family = AF_INET;   sin.sin_port   = (u_short)htons(port);   memcpy((char*)&sin.sin_addr, host->h_addr, host->h_length);   if ( connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0 ) {      int	err = errno;      errmsg = "Could not connect to host: ";      errmsg += name;      errmsg += ".\n" + SystemErrorMessage(err);      halApp->PopupMessage(errmsg);      CloseSocket();      return False;   }      // Start right in the TLS mode if told so   if ( imaps ) {      if ( !EnableTLS() ) {         CloseSocket();         return False;      }   }//// Wait for the server's response to see if the user must log in//   StringC	line;   if ( !GetLine(line) ) {      CloseSocket();      return False;   }   if ( line.StartsWith("* OK ") ) {      // OK; will need to log in later on      return True;   }   else if ( line.StartsWith("* BYE") ) { // Not accepted      line.CutBeg(5);      line.Trim();      errmsg = "The IMAP server on host ";      errmsg += name;      errmsg += "\nwould not accept a connection:\n\n";      errmsg += line;      halApp->PopupMessage(errmsg);      CloseSocket();      return False;   }   else if ( line.StartsWith("* PREAUTH") ) {      // Connection has already been authenticated by external means      authenticated = True;      return True;   }   else {      Unexpected(line);      CloseSocket();      return False;   }   return True;}/*------------------------------------------------------------------------ * Method to close socket (if it has been opened) */voidImapServerC::CloseSocket(){   if ( sock > 0 ) {      close(sock);   }   if ( TLSEnabled ) {      DisableTLS();   }   sock = 0;   connected     = False;   authenticated = False;}/*------------------------------------------------------------------------ * Method to start TLS session */BooleanImapServerC::StartTLS(){#ifdef HAVE_OPENSSL   if ( !haveStartTLS || TLSEnabled ) {      return False;   }   StringListC	output;   if ( !RunCommand("STARTTLS", output) ) return False;      return EnableTLS(TLS_VERSION_TLSV1);#else   return False;#endif}   #ifdef HAVE_OPENSSLstatic int verify_cert(int ok, X509_STORE_CTX *ctx){   X509 *serverCert;   char *certSubjectName, *certIssuerName;      // Get server's certificate   serverCert = X509_STORE_CTX_get_current_cert(ctx);   if ( !serverCert ) {      halApp->PopupMessage("No server certificate presented!", XmDIALOG_ERROR);      return False;   }      certSubjectName = X509_NAME_oneline(X509_get_subject_name(serverCert), 0, 0);   certIssuerName  = X509_NAME_oneline(X509_get_issuer_name(serverCert), 0, 0);      if ( debuglev ) {      cout << "Server certificate:"           << "\n\t subject: "           << certSubjectName           << "\n\t issuer: "           << certIssuerName           << endl;   }   if ( !ok ) {      StringC str = "Could not verify the following certificate:";      str += "\n   Subject: ";      str += certSubjectName;      str += "\n   Issued by: ";      str += certIssuerName;      str.Replace("/", "\n      ");      str += "\n\nReason: ";      str += X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));      str += ".\n\nAccept the certificate?";      if ( Query(str, *halApp, False) == QUERY_YES ) {         ok = True;         // Certificate path (TODO: configurable)         StringC certFile = ishApp->home + "/.ishmail.pem";         FILE *fp = fopen(certFile, "wa");         if (fp) {            PEM_write_X509(fp, serverCert);         }      }   }   return ok;}#endif/*------------------------------------------------------------------------ * Method to enable TLS negotiation supporting protocols of vers */BooleanImapServerC::EnableTLS(unsigned long vers){#ifdef HAVE_OPENSSL   if ( !sock || !(haveStartTLS || imaps) || TLSEnabled ) {      return False;   }      // Initialization   sslCtx      = NULL;   ssl         = NULL;      int err;   SSL_METHOD *meth;   if ( !sslInited ) {      if ( debuglev ) {         cout << "Initializing OpenSSL" << endl;      }      // For error messages      SSL_load_error_strings();      // Setup all the global SSL stuff      SSL_library_init();      sslInited = True;   }      Boolean sslv2_ok = vers & TLS_VERSION_SSLV2;   Boolean sslv3_ok = vers & TLS_VERSION_SSLV3;   Boolean tlsv1_ok = vers & TLS_VERSION_TLSV1;      if ( sslv2_ok && !sslv3_ok && !tlsv1_ok ) {      meth = SSLv2_client_method();   } else   if ( !sslv2_ok && sslv3_ok && tlsv1_ok ) {      meth = SSLv3_client_method();   } else   if ( !sslv2_ok && !sslv3_ok && tlsv1_ok ) {      meth = TLSv1_client_method();   } else {      meth = SSLv23_client_method();   }      sslCtx = SSL_CTX_new(meth);   if ( !sslCtx ) {      return False;   }   // set up CAs to look up   // Certificate path (TODO: configurable)   StringC certFile = ishApp->home + "/.ishmail.pem";   StringC certPath = OPENSSLDIR;   certPath += "/certs";   if (!SSL_CTX_load_verify_locations(sslCtx, certFile, certPath)) {      SSL_CTX_set_default_verify_paths(sslCtx);   }      SSL_CTX_set_verify(sslCtx, SSL_VERIFY_PEER, verify_cert);   SSL_CTX_set_verify_depth(sslCtx, 1);   // Start SSL negotiation   ssl = SSL_new(sslCtx);   if ( !ssl ) {      DisableTLS();      return False;   }      SSL_set_connect_state(ssl);   SSL_set_fd(ssl, sock);   int res = SSL_connect(ssl);   if ( res <= 0 ) {      err = SSL_get_error(ssl, res);      if ( err == SSL_ERROR_SYSCALL ) {         halApp->PopupMessage(SystemErrorMessage(errno));      }      // Broken STARTTLS implementation?      bugs |= IMAP_BUG_STARTTLS_BROKEN;      DisableTLS();      return False;   }   // Get the cipher   if ( debuglev ) {      cout << "SSL connection using " << SSL_get_cipher(ssl) << endl;   }   TLSEnabled = True;   return True;#else   return False;#endif}/*------------------------------------------------------------------------ * Method to end TLS negotiation and free respective structures */BooleanImapServerC::DisableTLS(){#ifdef HAVE_OPENSSL   if ( !haveStartTLS ) {      return False;   }      if ( ssl ) {      SSL_shutdown(ssl);      SSL_free(ssl);   }   if ( sslCtx ) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -