📄 imapserverc.c
字号:
SSL_CTX_free(sslCtx); } TLSEnabled = False; return True;#else return False;#endif}/*------------------------------------------------------------------------ * Method to authenticate against the IMAP server */BooleanImapServerC::DoLogin(){//// Do nothing if already (pre)authenticated// if ( authenticated ) return True; StringC errmsg; while ( True ) {//// Get user id and password// if ( !GetLogin(name, user, pass) ) { // User cancelled return False; }//// Send login command// ImapCommandReturn res = Authenticate(user, pass); switch ( res ) { case ImapCommandOK: return True; break; case ImapCommandNoConnect: // An error message should be issued by a low-level function return False; break; case ImapCommandCancelled: // User cancelled; just return return False; break; case ImapCommandNO: // Wrong user/pass errmsg = "The IMAP server on host "; errmsg += name; errmsg += "\ndenied access."; break; default: // ?? Not-supported protocol or our bug errmsg = "An authentication error ocured while connecting to server."; errmsg += name; break; } InvalidateLogin(name); errmsg += "\n\nRetry?"; if ( !RetryLogin(errmsg) ) { return False; } } // End while not logged in}/*------------------------------------------------------------------------ * Method to reconnect to the IMAP server */BooleanImapServerC::ReConnect(){ if ( EstablishSession() ) { ishApp->mainWin->curFolder->Rescan(); return True; } else return False;}/*------------------------------------------------------------------------ * Method to determine the IMAP server capabilities */BooleanImapServerC::Capability(){ protocols = 0L; authMethods = 0L; // STARTTLS may not be announced after switching to TLS if ( !TLSEnabled ) { haveStartTLS = False; } // all servers support LOGIN unless explicitly said otherwise Boolean loginDisabled = False; //// Issue the CAPABILITY command// StringListC output; if ( RunCommand("CAPABILITY", output) ) {//// Loop through the output looking for BAD response. If found, this is// an IMAP 2 server. Otherwise, get some valuable info (supported protocols,// authentication schemes etc)// u_int count = output.size(); for (int i=0; i<count; i++) { StringC *line = output[i]; if ( line->StartsWith("BAD", IGNORE_CASE) ) { protocols = IMAP_PROTOCOL_IMAP2BIS; // Stick with IMAP2bis break; } else { StringListC tokens; ExtractList(*line, tokens); int ntokens = tokens.size(); for (int j = 0; j < ntokens; j++) { StringC *token = tokens[j]; if ( token->Equals("IMAP4", IGNORE_CASE) ) { protocols |= IMAP_PROTOCOL_IMAP4; } else if ( token->Equals("IMAP4rev1", IGNORE_CASE) ) { protocols |= IMAP_PROTOCOL_IMAP4REV1; } else if ( token->Equals("AUTH=LOGIN", IGNORE_CASE) ) { authMethods |= IMAP_AUTH_LOGIN; } else if ( token->Equals("AUTH=ANONYMOUS", IGNORE_CASE) ) { authMethods |= IMAP_AUTH_ANONYMOUS; }#ifdef HAVE_OPENSSL else if ( token->Equals("AUTH=CRAM-MD5", IGNORE_CASE) ) { authMethods |= IMAP_AUTH_CRAM_MD5; }#endif#if 0 else if ( token->Equals("AUTH=GSSAPI", IGNORE_CASE) ) { authMethods |= IMAP_AUTH_GSSAPI; } else if ( token->Equals("AUTH=KERBEROS_V4", IGNORE_CASE) ) { authMethods |= IMAP_AUTH_KERBEROS_V4; }#endif else if ( token->Equals("LOGINDISABLED", IGNORE_CASE) ) { loginDisabled = True; } else if ( token->Equals("STARTTLS", IGNORE_CASE) ) { haveStartTLS = True; } } } } if ( !loginDisabled ) { authMethods |= IMAP_AUTH_CLEAR_TEXT; } if ( !protocols ) { // No supported protocols found StringC errmsg; errmsg = "The IMAP server on host "; errmsg += name; errmsg += "\ndoes not support any known IMAP protocol\n"; halApp->PopupMessage(errmsg); return False; } else if ( !authMethods ) { // No supported authentication methods StringC errmsg; errmsg = "The IMAP server on host "; errmsg += name; errmsg += "\nfeatures no supported authentication methods\n"; halApp->PopupMessage(errmsg); return False; } else { return True; } } else { return False; }} // End Capability/*------------------------------------------------------------------------ * Function to find or open a connection to the specified IMAP server */ImapServerC*FindImapServer(const char *hostname, long port, Boolean imaps, const char *username){//// See if this one is already connected// if ( !serverList ) serverList = new PtrListC; u_int count = serverList->size(); for (int i=0; i<count; i++) { ImapServerC *server = (ImapServerC*)*(*serverList)[i]; if ( server->name == hostname && server->port == port && server->user == username ) return server; }//// Create a new server object// ImapServerC *server = new ImapServerC(hostname, username, port, imaps); return server;} // End FindImapServer/*------------------------------------------------------------------------ * An old restricted form of the above. Should be eventually removed */ImapServerC*FindImapServer(const char *hostname){ if ( !serverList ) serverList = new PtrListC; u_int count = serverList->size(); for (int i=0; i<count; i++) { ImapServerC *server = (ImapServerC*)*(*serverList)[i]; if ( server->name == hostname ) return server; } ImapServerC *server = new ImapServerC(hostname); return server;} // End FindImapServer/*------------------------------------------------------------------------ * Function to close the connections to all IMAP servers */voidCloseImapServerConnections(){ if ( !serverList ) return; u_int count = serverList->size(); for (int i=count-1; i>=0; i--) { ImapServerC *server = (ImapServerC*)*(*serverList)[i]; delete server; } serverList->removeAll(); delete serverList;} // CloseImapServerConnections/*------------------------------------------------------------------------ * Function to return the next line from the server */BooleanImapServerC::GetLine(StringC& line){ StringC errmsg; char buf[IMAP_MAXLINE+1]; buf[0] = 0;//// Return the first line in the list// if ( lineList->size() > 0 ) { line = *(*lineList)[0]; lineList->remove((u_int)0); if ( debuglev > 1 ) cout <<"<< [" <<line <<"]" <<endl; return True; } line.Clear(); StringC curLine(lastBuf); CharC bufStr; int readCount;#ifdef HAVE_OPENSSL if ( TLSEnabled ) { while (True) { readCount = SSL_read(ssl, buf, IMAP_MAXLINE); if ( readCount <= 0 ) { // FIXME: proper check return False; } buf[readCount] = 0; bufStr = buf; // // If there's no newline, save this buffer and read some more // int pos = bufStr.PosOf('\n'); if ( pos < 0 ) { curLine += bufStr; bufStr.CutBeg(bufStr.Length()); } // // Extract lines from the buffer // else while ( pos >= 0 ) { curLine += bufStr(0,pos); // Copy up to newline if ( curLine.EndsWith('\r') ) curLine.CutEnd(1); // // See if this line is to be returned // if ( line.size() == 0 ) line = curLine; else lineList->add(curLine); // // Look for another line // lastBuf[0] = 0; bufStr.CutBeg(pos+1); curLine.Clear(); pos = bufStr.PosOf('\n'); } // End for each newline in buffer // // If we found a match, we're done // if ( line.size() > 0 ) { if ( debuglev > 1 ) cout <<"<< [" <<line <<"]" <<endl; strcpy(lastBuf, bufStr.Addr()); return True; } // // Copy whatever's left into lastBuf // //strcpy(lastBuf, bufStr.Addr()); if (bufStr.Length() > 0) curLine += bufStr(0,bufStr.Length()); } return True; }#endif//// Read lines until we find a match// fd_set readSet; FD_ZERO(&readSet); struct timeval timeout; while ( True ) {//// Check the socket// int rc; while (True) { FD_SET(sock, &readSet); timeout.tv_sec = 10; timeout.tv_usec = 0; rc = select(sock+1/*width*/, &readSet, NULL, NULL, &timeout); // // data is available on some socket // if ( rc > 0 ) break; // // error occurred // else if ( rc < 0) { if ( errno == EINTR ) { if (debuglev > 0) cout << "Select got SIGINTR, retrying" << endl; } else { StringC errmsg; int err = errno; errmsg = "Could not select socket "; errmsg += sock; errmsg += " for IMAP server "; errmsg += name; errmsg += ".\n" + SystemErrorMessage(err); halApp->PopupMessage(errmsg); return False; } } // // timeout // else if ( rc == 0 ) { CloseSocket(); errmsg = "Timeout trying to select the IMAP server\n"; errmsg += "\n\nRetry?"; if ( RetryLogin(errmsg) ) { // // Try to reconnect. Regardless of whether it works, return // "False" here so the the operation will be re-tried from // the beginning. // connected = ReConnect(); } return False; } }//// See if there is data for us// if ( !FD_ISSET(sock, &readSet) ) continue; readCount = read(sock, buf, IMAP_MAXLINE); if ( readCount == 0 ) { CloseSocket(); errmsg = "Timeout trying to select the IMAP server\n"; errmsg += "\n\nRetry?"; if ( RetryLogin(errmsg) ) { // // Try to reconnect. Regardless of whether it works, return // "False" here so the the operation will be re-tried from // the beginning. // connected = ReConnect(); } return False; } else if ( readCount < 0 ) { StringC errmsg; int err = errno; errmsg = "Could not read socket "; errmsg += sock; errmsg += " for IMAP server "; errmsg += name; errmsg += ".\n" + SystemErrorMessage(err); halApp->PopupMessage(errmsg); return False; } buf[readCount] = 0; if ( debuglev > 2 ) cout <<"Buffer [" <<buf <<"]" <<endl; bufStr = buf;//// If there's no newline, save this buffer and read some more// int pos = bufStr.PosOf('\n'); if ( pos < 0 ) { curLine += bufStr; bufStr.CutBeg(bufStr.Length()); }//// Extract lines from the buffer// else while ( pos >= 0 ) { curLine += bufStr(0,pos); // Copy up to newline if ( curLine.EndsWith('\r') ) curLine.CutEnd(1);//// See if this line is to be returned// if ( line.size() == 0 ) line = curLine; else lineList->add(curLine);//// Look for another line// lastBuf[0] = 0; bufStr.CutBeg(pos+1); curLine.Clear(); pos = bufStr.PosOf('\n'); } // End for each newline in buffer//// If we found a match, we're done// if ( line.size() > 0 ) { if ( debuglev > 1 ) cout <<"<< [" <<line <<"]" <<endl; strcpy(lastBuf, bufStr.Addr()); return True; }//// Copy whatever's left into lastBuf// //strcpy(lastBuf, bufStr.Addr()); if (bufStr.Length() > 0) curLine += bufStr(0,bufStr.Length()); } // End while no matching line has been read} // End GetLine/*------------------------------------------------------------------------ * Function to send a command to the server */BooleanImapServerC::PutLine(CharC line, Boolean terminate){ StringC errmsg; if ( debuglev > 0 ) { int pos = -1; char *esc; if ( TLSEnabled ) { esc = "[01;32m>> ["; } else { esc = "[1m>> ["; } if ( line.Contains(" LOGIN ") ) pos = line.RevPosOf(' '); cout <<esc << ((pos >= 0) ? line(0,pos):line) <<"][0m" <<endl; } StringC linebuf(line);//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -