📄 inetmail.cxx
字号:
}void PSMTPServer::OnVRFY(const PCaselessString & name){ PString expandedName; switch (LookUpName(name, expandedName)) { case AmbiguousUser : WriteResponse(553, "User \"" + name + "\" ambiguous."); break; case ValidUser : WriteResponse(250, expandedName); break; case UnknownUser : WriteResponse(550, "Name \"" + name + "\" does not match anything."); break; default : WriteResponse(550, "Error verifying user \"" + name + "\"."); }}void PSMTPServer::OnEXPN(const PCaselessString &){ WriteResponse(502, "I don't do that. Sorry.");}static PINDEX ParseMailPath(const PCaselessString & args, const PCaselessString & subCmd, PString & name, PString & domain, PString & forwardList){ PINDEX colon = args.Find(':'); if (colon == P_MAX_INDEX) return 0; PCaselessString word = args.Left(colon).Trim(); if (subCmd != word) return 0; PINDEX leftAngle = args.Find('<', colon); if (leftAngle == P_MAX_INDEX) return 0; PINDEX finishQuote; PINDEX startQuote = args.Find('"', leftAngle); if (startQuote == P_MAX_INDEX) { colon = args.Find(':', leftAngle); if (colon == P_MAX_INDEX) colon = leftAngle; finishQuote = startQuote = colon+1; } else { finishQuote = args.Find('"', startQuote+1); if (finishQuote == P_MAX_INDEX) finishQuote = startQuote; colon = args.Find(':', leftAngle); if (colon > startQuote) colon = leftAngle; } PINDEX rightAngle = args.Find('>', finishQuote); if (rightAngle == P_MAX_INDEX) return 0; PINDEX at = args.Find('@', finishQuote); if (at > rightAngle) at = rightAngle; if (startQuote == finishQuote) finishQuote = at; name = args(startQuote, finishQuote-1); domain = args(at+1, rightAngle-1); forwardList = args(leftAngle+1, colon-1); return rightAngle+1;}void PSMTPServer::OnRCPT(const PCaselessString & recipient){ PCaselessString toName; PCaselessString toDomain; PCaselessString forwardList; if (ParseMailPath(recipient, "to", toName, toDomain, forwardList) == 0) WriteResponse(501, "Syntax error."); else { switch (ForwardDomain(toDomain, forwardList)) { case CannotForward : WriteResponse(550, "Cannot do forwarding."); break; case WillForward : if (!forwardList) forwardList += ":"; forwardList += toName; if (!toDomain) forwardList += "@" + toDomain; toNames.AppendString(toName); toDomains.AppendString(forwardList); break; case LocalDomain : { PString expandedName; switch (LookUpName(toName, expandedName)) { case ValidUser : WriteResponse(250, "Recipient " + toName + " Ok"); toNames.AppendString(toName); toDomains.AppendString(""); break; case AmbiguousUser : WriteResponse(553, "User ambiguous."); break; case UnknownUser : WriteResponse(550, "User unknown."); break; default : WriteResponse(550, "Error verifying user."); } } } }}void PSMTPServer::OnMAIL(const PCaselessString & sender){ sendCommand = WasMAIL; OnSendMail(sender);}void PSMTPServer::OnSEND(const PCaselessString & sender){ sendCommand = WasSEND; OnSendMail(sender);}void PSMTPServer::OnSAML(const PCaselessString & sender){ sendCommand = WasSAML; OnSendMail(sender);}void PSMTPServer::OnSOML(const PCaselessString & sender){ sendCommand = WasSOML; OnSendMail(sender);}void PSMTPServer::OnSendMail(const PCaselessString & sender){ if (!fromAddress) { WriteResponse(503, "Sender already specified."); return; } PString fromDomain; PINDEX extendedArgPos = ParseMailPath(sender, "from", fromAddress, fromDomain, fromPath); if (extendedArgPos == 0 || fromAddress.IsEmpty()) { WriteResponse(501, "Syntax error."); return; } fromAddress += fromDomain; if (extendedHello) { PINDEX equalPos = sender.Find('=', extendedArgPos); PCaselessString body = sender(extendedArgPos, equalPos).Trim(); PCaselessString mime = sender.Mid(equalPos+1).Trim(); eightBitMIME = (body == "BODY" && mime == "8BITMIME"); } PString response = "Sender " + fromAddress; if (eightBitMIME) response += " and 8BITMIME"; WriteResponse(250, response + " Ok");}void PSMTPServer::OnDATA(){ if (fromAddress.IsEmpty()) { WriteResponse(503, "Need a valid MAIL command."); return; } if (toNames.GetSize() == 0) { WriteResponse(503, "Need a valid RCPT command."); return; } // Ok, everything is ready to start the message. if (!WriteResponse(354, eightBitMIME ? "Enter 8BITMIME message, terminate with '<CR><LF>.<CR><LF>'." : "Enter mail, terminate with '.' alone on a line.")) return; endMIMEDetectState = eightBitMIME ? StuffIdle : DontStuff; BOOL ok = TRUE; BOOL completed = FALSE; BOOL starting = TRUE; while (ok && !completed) { PCharArray buffer; if (eightBitMIME) ok = OnMIMEData(buffer, completed); else ok = OnTextData(buffer, completed); if (ok) { ok = HandleMessage(buffer, starting, completed); starting = FALSE; } } if (ok) WriteResponse(250, "Message received Ok."); else WriteResponse(554, "Message storage failed.");}BOOL PSMTPServer::OnUnknown(const PCaselessString & command){ WriteResponse(500, "Command \"" + command + "\" unrecognised."); return TRUE;}BOOL PSMTPServer::OnTextData(PCharArray & buffer, BOOL & completed){ PString line; while (ReadLine(line)) { PINDEX len = line.GetLength(); if (len == 1 && line[0] == '.') { completed = TRUE; return TRUE; } PINDEX start = (len > 1 && line[0] == '.' && line[1] == '.') ? 1 : 0; PINDEX size = buffer.GetSize(); len -= start; memcpy(buffer.GetPointer(size + len + 2) + size, ((const char *)line)+start, len); size += len; buffer[size++] = '\r'; buffer[size++] = '\n'; if (size > messageBufferSize) return TRUE; } return FALSE;}BOOL PSMTPServer::OnMIMEData(PCharArray & buffer, BOOL & completed){ PINDEX count = 0; int c; while ((c = ReadChar()) >= 0) { if (count >= buffer.GetSize()) buffer.SetSize(count + 100); switch (endMIMEDetectState) { case StuffIdle : buffer[count++] = (char)c; break; case StuffCR : endMIMEDetectState = c != '\n' ? StuffIdle : StuffCRLF; buffer[count++] = (char)c; break; case StuffCRLF : if (c == '.') endMIMEDetectState = StuffCRLFdot; else { endMIMEDetectState = StuffIdle; buffer[count++] = (char)c; } break; case StuffCRLFdot : switch (c) { case '\r' : endMIMEDetectState = StuffCRLFdotCR; break; case '.' : endMIMEDetectState = StuffIdle; buffer[count++] = (char)c; break; default : endMIMEDetectState = StuffIdle; buffer[count++] = '.'; buffer[count++] = (char)c; } break; case StuffCRLFdotCR : if (c == '\n') { completed = TRUE; return TRUE; } buffer[count++] = '.'; buffer[count++] = '\r'; buffer[count++] = (char)c; endMIMEDetectState = StuffIdle; default : PAssertAlways("Illegal SMTP state"); } if (count > messageBufferSize) { buffer.SetSize(messageBufferSize); return TRUE; } } return FALSE;}PSMTPServer::ForwardResult PSMTPServer::ForwardDomain(PCaselessString & userDomain, PCaselessString & forwardDomainList){ return userDomain.IsEmpty() && forwardDomainList.IsEmpty() ? LocalDomain : CannotForward;}PSMTPServer::LookUpResult PSMTPServer::LookUpName(const PCaselessString &, PString & expandedName){ expandedName = PString(); return LookUpError;}BOOL PSMTPServer::HandleMessage(PCharArray &, BOOL, BOOL){ return FALSE;}//////////////////////////////////////////////////////////////////////////////// PPOP3static char const * const POP3Commands[PPOP3::NumCommands] = { "USER", "PASS", "QUIT", "RSET", "NOOP", "STAT", "LIST", "RETR", "DELE", "APOP", "TOP", "UIDL", "AUTH"};PString PPOP3::okResponse = "+OK";PString PPOP3::errResponse = "-ERR";PPOP3::PPOP3() : PInternetProtocol("pop3 110", NumCommands, POP3Commands){}PINDEX PPOP3::ParseResponse(const PString & line){ lastResponseCode = line[0] == '+'; PINDEX endCode = line.Find(' '); if (endCode != P_MAX_INDEX) lastResponseInfo = line.Mid(endCode+1); else lastResponseInfo = PString(); return 0;}//////////////////////////////////////////////////////////////////////////////// PPOP3ClientPPOP3Client::PPOP3Client(){ loggedIn = FALSE;}PPOP3Client::~PPOP3Client(){ Close();}BOOL PPOP3Client::OnOpen(){ if (!ReadResponse() || lastResponseCode <= 0) return FALSE; // APOP login command supported? PINDEX i = lastResponseInfo.FindRegEx("<.*@.*>"); if (i != P_MAX_INDEX) apopBanner = lastResponseInfo.Mid(i); return TRUE;}BOOL PPOP3Client::Close(){ BOOL ok = TRUE; if (IsOpen() && loggedIn) { SetReadTimeout(60000); ok = ExecuteCommand(QUIT, "") > 0; } return PInternetProtocol::Close() && ok;}BOOL PPOP3Client::LogIn(const PString & username, const PString & password, int options){#if P_SASL2 PString mech; PSASLClient auth("pop", username, username, password); if ((options & UseSASL) && ExecuteCommand(AUTH, "") > 0) { PStringSet serverMechs; while (ReadLine(mech) && mech[0] != '.') serverMechs.Include(mech); mech = PString::Empty(); PStringSet ourMechs; if (auth.Init("", ourMechs)) { if (!(options & AllowClearTextSASL)) { ourMechs.Exclude("PLAIN"); ourMechs.Exclude("LOGIN"); } for (PINDEX i = 0, max = serverMechs.GetSize() ; i < max ; i++) if (ourMechs.Contains(serverMechs.GetKeyAt(i))) { mech = serverMechs.GetKeyAt(i); break; } } } PString output; if ((options & UseSASL) && !mech.IsEmpty() && auth.Start(mech, output)) { if (ExecuteCommand(AUTH, mech) <= 0) return FALSE; PSASLClient::PSASLResult result; do { result = auth.Negotiate(lastResponseInfo, output); if (result == PSASLClient::Fail) return FALSE; if (!output.IsEmpty()) { WriteLine(output); if (!ReadResponse() || !lastResponseCode) return FALSE; } } while (result == PSASLClient::Continue); auth.End(); } else {#endif if (!apopBanner.IsEmpty()) { // let's try with APOP PMessageDigest::Result bin_digest; PMessageDigest5::Encode(apopBanner + password, bin_digest); PString digest; const BYTE * data = bin_digest.GetPointer(); for (PINDEX i = 0, max = bin_digest.GetSize(); i < max ; i++) digest.sprintf("%02x", (unsigned)data[i]); if (ExecuteCommand(APOP, username + " " + digest) > 0) return loggedIn = TRUE; } // No SASL and APOP didn't work for us // If we really have to, we'll go with the plain old USER/PASS scheme if (!(options & AllowUserPass)) return FALSE; if (ExecuteCommand(USER, username) <= 0) return FALSE; if (ExecuteCommand(PASS, password) <= 0) return FALSE;#if P_SASL2 }#endif loggedIn = TRUE; return TRUE;}int PPOP3Client::GetMessageCount(){ if (ExecuteCommand(STATcmd, "") <= 0) return -1; return (int)lastResponseInfo.AsInteger();}PUnsignedArray PPOP3Client::GetMessageSizes(){ PUnsignedArray sizes; if (ExecuteCommand(LIST, "") > 0) { PString msgInfo; while (ReadLine(msgInfo) && isdigit(msgInfo[0])) sizes.SetAt((PINDEX)msgInfo.AsInteger()-1,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -