📄 inetmail.cxx
字号:
/* * inetmail.cxx * * Internet Mail classes. * * Portable Windows Library * * Copyright (c) 1993-2002 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): Federico Pinna and Reitek S.p.A. (SASL authentication) * * $Log: inetmail.cxx,v $ * Revision 1.30 2004/05/09 07:23:49 rjongbloed * More work on XMPP, thanks Federico Pinna and Reitek S.p.A. * * Revision 1.29 2004/05/02 08:58:15 csoutheren * Removed warnings when compling without SASL * * Revision 1.28 2004/04/28 11:26:43 csoutheren * Hopefully fixed SASL and SASL2 problems * * Revision 1.27 2004/04/26 01:33:20 rjongbloed * Fixed minor problem with SASL authentication, thanks Federico Pinna, Reitek S.p.A. * * Revision 1.26 2004/04/21 00:29:56 csoutheren * Added SASL authentication to PPOP3Client and PSMTPClient * Thanks to Federico Pinna and Reitek S.p.A. * * Revision 1.25 2004/04/03 06:54:25 rjongbloed * Many and various changes to support new Visual C++ 2003 * * Revision 1.24 2003/02/20 00:16:06 craigs * Changed MIME_Version to MIME-Version * * Revision 1.23 2002/12/19 01:35:24 robertj * Fixed problem with returning incorrect lastWriteLength on translated output. * * Revision 1.22 2002/11/06 22:47:25 robertj * Fixed header comment (copyright etc) * * Revision 1.21 2002/01/07 05:26:47 robertj * Fixed getting scan list of messages, thanks xradish * * Revision 1.20 2001/09/28 00:45:27 robertj * Removed HasKey() as is confusing due to ancestor Contains(). * * Revision 1.19 2000/11/21 01:49:25 robertj * Fixed warning on GNU compiler. * * Revision 1.18 2000/11/16 07:15:15 robertj * Fixed problem with not closing off base64 encoding at next MIME part. * * Revision 1.17 2000/11/14 08:30:03 robertj * Fixed bug in closing SMTP client, conditional around wrong way. * * Revision 1.16 2000/11/10 01:08:11 robertj * Added content transfer encoding and automatic base64 translation. * * Revision 1.15 2000/11/09 06:01:58 robertj * Added MIME version and content disposition to RFC822 class. * * Revision 1.14 2000/11/09 05:50:23 robertj * Added RFC822 aware channel class for doing internet mail. * * Revision 1.13 2000/06/21 01:01:22 robertj * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at). * * Revision 1.12 1998/11/30 04:52:01 robertj * New directory structure * * Revision 1.11 1998/09/23 06:22:18 robertj * Added open source copyright license. * * Revision 1.10 1998/01/26 02:49:20 robertj * GNU support. * * Revision 1.9 1997/07/14 11:47:14 robertj * Added "const" to numerous variables. * * Revision 1.8 1996/12/21 01:24:39 robertj * Added missing open message to smtp server. * * Revision 1.7 1996/09/14 13:18:03 robertj * Renamed file and changed to be a protocol off new indirect channel to separate * the protocol from the low level byte transport channel. * * Revision 1.6 1996/07/27 04:12:45 robertj * Redesign and reimplement of mail sockets. * * Revision 1.5 1996/06/28 13:22:09 robertj * Changed SMTP incoming message handler so can tell when started, processing or ended message. * * Revision 1.4 1996/05/26 03:46:51 robertj * Compatibility to GNU 2.7.x * * Revision 1.3 1996/03/18 13:33:16 robertj * Fixed incompatibilities to GNU compiler where PINDEX != int. * * Revision 1.2 1996/03/16 04:51:28 robertj * Changed lastResponseCode to an integer. * Added ParseReponse() for splitting reponse line into code and info. * * Revision 1.1 1996/03/04 12:12:51 robertj * Initial revision * */#ifdef __GNUC__#pragma implementation "inetmail.h"#endif#include <ptlib.h>#include <ptlib/sockets.h>#include <ptclib/inetmail.h>#if P_SASL2#include <ptclib/psasl.h>#endifstatic const PString CRLF = "\r\n";static const PString CRLFdotCRLF = "\r\n.\r\n";//////////////////////////////////////////////////////////////////////////////// PSMTPstatic char const * const SMTPCommands[PSMTP::NumCommands] = { "HELO", "EHLO", "QUIT", "HELP", "NOOP", "TURN", "RSET", "VRFY", "EXPN", "RCPT", "MAIL", "SEND", "SAML", "SOML", "DATA", "AUTH"};PSMTP::PSMTP() : PInternetProtocol("smtp 25", NumCommands, SMTPCommands){}//////////////////////////////////////////////////////////////////////////////// PSMTPClientPSMTPClient::PSMTPClient(){ haveHello = FALSE; extendedHello = FALSE; eightBitMIME = FALSE;}PSMTPClient::~PSMTPClient(){ Close();}BOOL PSMTPClient::OnOpen(){ return ReadResponse() && lastResponseCode/100 == 2;}BOOL PSMTPClient::Close(){ BOOL ok = TRUE; if (sendingData) ok = EndMessage(); if (IsOpen() && haveHello) { SetReadTimeout(60000); ok = ExecuteCommand(QUIT, "")/100 == 2 && ok; } return PInternetProtocol::Close() && ok;}#if P_SASL2BOOL PSMTPClient::LogIn(const PString & username, const PString & password){ PString localHost; PIPSocket * socket = GetSocket(); if (socket != NULL) { localHost = socket->GetLocalHostName(); } if (haveHello) return FALSE; // Wrong state if (ExecuteCommand(EHLO, localHost)/100 != 2) return TRUE; // EHLO not supported, therefore AUTH not supported haveHello = extendedHello = TRUE; PStringArray caps = lastResponseInfo.Lines(); PStringArray serverMechs; PINDEX i, max; for (i = 0, max = caps.GetSize() ; i < max ; i++) if (caps[i].Left(5) == "AUTH ") { serverMechs = caps[i].Mid(5).Tokenise(" ", FALSE); break; } if (serverMechs.GetSize() == 0) return TRUE; // No mechanisms, no login PSASLClient auth("smtp", username, username, password); PStringSet ourMechs; if (!auth.Init("", ourMechs)) return FALSE; PString mech; for (i = 0, max = serverMechs.GetSize() ; i < max ; i++) if (ourMechs.Contains(serverMechs[i])) { mech = serverMechs[i]; break; } if (mech.IsEmpty()) return TRUE; // No mechanism in common PString output; // Ok, let's go... if (!auth.Start(mech, output)) return FALSE; if (!output.IsEmpty()) mech = mech + " " + output; if (ExecuteCommand(AUTH, mech) <= 0) return FALSE; PSASLClient::PSASLResult result; int response; do { response = lastResponseCode/100; if (response == 2) break; else if (response != 3) return FALSE; result = auth.Negotiate(lastResponseInfo, output); if (result == PSASLClient::Fail) return FALSE; if (!output.IsEmpty()) { WriteLine(output); if (!ReadResponse()) return FALSE; } } while (result == PSASLClient::Continue); auth.End(); return TRUE;}#elseBOOL PSMTPClient::LogIn(const PString &, const PString &){ return TRUE;}#endifBOOL PSMTPClient::BeginMessage(const PString & from, const PString & to, BOOL useEightBitMIME){ fromAddress = from; toNames.RemoveAll(); toNames.AppendString(to); eightBitMIME = useEightBitMIME; return _BeginMessage();}BOOL PSMTPClient::BeginMessage(const PString & from, const PStringList & toList, BOOL useEightBitMIME){ fromAddress = from; toNames = toList; eightBitMIME = useEightBitMIME; return _BeginMessage();}BOOL PSMTPClient::_BeginMessage(){ PString localHost; PString peerHost; PIPSocket * socket = GetSocket(); if (socket != NULL) { localHost = socket->GetLocalHostName(); peerHost = socket->GetPeerHostName(); } if (!haveHello) { if (ExecuteCommand(EHLO, localHost)/100 == 2) haveHello = extendedHello = TRUE; } if (!haveHello) { extendedHello = FALSE; if (eightBitMIME) return FALSE; if (ExecuteCommand(HELO, localHost)/100 != 2) return FALSE; haveHello = TRUE; } if (fromAddress[0] != '"' && fromAddress.Find(' ') != P_MAX_INDEX) fromAddress = '"' + fromAddress + '"'; if (!localHost && fromAddress.Find('@') == P_MAX_INDEX) fromAddress += '@' + localHost; if (ExecuteCommand(MAIL, "FROM:<" + fromAddress + '>')/100 != 2) return FALSE; for (PINDEX i = 0; i < toNames.GetSize(); i++) { if (!peerHost && toNames[i].Find('@') == P_MAX_INDEX) toNames[i] += '@' + peerHost; if (ExecuteCommand(RCPT, "TO:<" + toNames[i] + '>')/100 != 2) return FALSE; } if (ExecuteCommand(DATA, PString())/100 != 3) return FALSE; stuffingState = StuffIdle; sendingData = TRUE; return TRUE;}BOOL PSMTPClient::EndMessage(){ flush(); stuffingState = DontStuff; sendingData = FALSE; if (!WriteString(CRLFdotCRLF)) return FALSE; return ReadResponse() && lastResponseCode/100 == 2;}//////////////////////////////////////////////////////////////////////////////// PSMTPServerPSMTPServer::PSMTPServer(){ extendedHello = FALSE; eightBitMIME = FALSE; messageBufferSize = 30000; ServerReset();}void PSMTPServer::ServerReset(){ eightBitMIME = FALSE; sendCommand = WasMAIL; fromAddress = PString(); toNames.RemoveAll();}BOOL PSMTPServer::OnOpen(){ return WriteResponse(220, PIPSocket::GetHostName() + "ESMTP server ready");}BOOL PSMTPServer::ProcessCommand(){ PString args; PINDEX num; if (!ReadCommand(num, args)) return FALSE; switch (num) { case HELO : OnHELO(args); break; case EHLO : OnEHLO(args); break; case QUIT : OnQUIT(); return FALSE; case NOOP : OnNOOP(); break; case TURN : OnTURN(); break; case RSET : OnRSET(); break; case VRFY : OnVRFY(args); break; case EXPN : OnEXPN(args); break; case RCPT : OnRCPT(args); break; case MAIL : OnMAIL(args); break; case SEND : OnSEND(args); break; case SAML : OnSAML(args); break; case SOML : OnSOML(args); break; case DATA : OnDATA(); break; default : return OnUnknown(args); } return TRUE;}void PSMTPServer::OnHELO(const PCaselessString & remoteHost){ extendedHello = FALSE; ServerReset(); PCaselessString peerHost; PIPSocket * socket = GetSocket(); if (socket != NULL) peerHost = socket->GetPeerHostName(); PString response = PIPSocket::GetHostName() & "Hello" & peerHost + ", "; if (remoteHost == peerHost) response += "pleased to meet you."; else if (remoteHost.IsEmpty()) response += "why do you wish to remain anonymous?"; else response += "why do you wish to call yourself \"" + remoteHost + "\"?"; WriteResponse(250, response);}void PSMTPServer::OnEHLO(const PCaselessString & remoteHost){ extendedHello = TRUE; ServerReset(); PCaselessString peerHost; PIPSocket * socket = GetSocket(); if (socket != NULL) peerHost = socket->GetPeerHostName(); PString response = PIPSocket::GetHostName() & "Hello" & peerHost + ", "; if (remoteHost == peerHost) response += ", pleased to meet you."; else if (remoteHost.IsEmpty()) response += "why do you wish to remain anonymous?"; else response += "why do you wish to call yourself \"" + remoteHost + "\"?"; response += "\nHELP\nVERB\nONEX\nMULT\nEXPN\nTICK\n8BITMIME\n"; WriteResponse(250, response);}void PSMTPServer::OnQUIT(){ WriteResponse(221, PIPSocket::GetHostName() + " closing connection, goodbye."); Close();}void PSMTPServer::OnHELP(){ WriteResponse(214, "No help here.");}void PSMTPServer::OnNOOP(){ WriteResponse(250, "Ok");}void PSMTPServer::OnTURN(){ WriteResponse(502, "I don't do that yet. Sorry.");}void PSMTPServer::OnRSET(){ ServerReset(); WriteResponse(250, "Reset state.");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -