// rdsendmail.cpp // // Send an e-mail message using sendmail(1) // // (C) Copyright 2020 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // 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. // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. // #include #include "rdsendmail.h" #include "rduser.h" #include bool __RDSendMail_IsAscii(const QString &str) { for(int i=0;i127)||(ch.row()>0)) { return false; } } return true; } QByteArray __RDSendMail_EncodeBody(QString *charset,QString *encoding, const QString &str) { QByteArray raw; int index=0; QByteArray ret; if(__RDSendMail_IsAscii(str)) { // // All 7 Bit Characters // *charset=""; *encoding=""; // // Ensure no naked CR or LF characters (RFC5322 Section 2.3) // ret=str.toAscii(); index=0; while((index=ret.indexOf("/r",index))>=0) { if(ret.mid(index+1,1)!="/n") { ret.insert(index+1,"/n"); index++; } } index=0; while((index=ret.indexOf("\n",index))>=0) { if((index==0)||(ret.mid(index-1,1)!="\r")) { ret.insert(index,"\r"); index+=2; } } return ret; } // // 8+ Bit Characters // *charset=";charset=utf8"; *encoding="Content-Transfer-Encoding: base64\r\n"; raw=str.toUtf8(); for(int i=0;i")) { start=str.indexOf("<"); end=str.indexOf(">"); if(start" format // // FIXME: Add support for IDNA (see RFC5891) // if(name.isEmpty()) { return addr.toAscii(); } return __RDSendMail_EncodeHeader(name)+" <"+addr.toAscii()+">"; } // // This implements a basic email sending capability using the system's // sendmail(1) interface. // bool RDSendMail(QString *err_msg,const QString &subject,const QString &body, const QString &from_addr,const QStringList &to_addrs, const QStringList &cc_addrs,const QStringList &bcc_addrs, bool dry_run) { QStringList args; QProcess *proc=NULL; QString msg=""; QByteArray from_addr_enc; QList to_addrs_enc; QList cc_addrs_enc; QList bcc_addrs_enc; bool ok=false; *err_msg=""; // // Validate Addresses // if(from_addr.isEmpty()) { *err_msg+=QObject::tr("You must supply a \"from\" address")+"\n"; } else { from_addr_enc=__RDSendMail_EncodeAddress(from_addr,&ok); if(!ok) { *err_msg+=QObject::tr("address")+" \""+from_addr+"\" "+ QObject::tr("is invalid")+"\n"; } } for(int i=0;iisEmpty()) { return false; } // // Compose Message // QString charset; QString encoding; QByteArray raw=__RDSendMail_EncodeBody(&charset,&encoding,body); msg+="From: "+from_addr_enc+"\r\n"; msg+="Content-Type: text/plain"+charset+"\r\n"; msg+=encoding; if(to_addrs_enc.size()>0) { msg+="To: "; for(int i=0;i0) { msg+="Cc: "; for(int i=0;i0) { msg+="Bcc: "; for(int i=0;istart("sendmail",args); if(!proc->waitForStarted()) { *err_msg=QObject::tr("unable to start sendmail")+"\n"; delete proc; return false; } proc->write(msg.toUtf8()); proc->closeWriteChannel(); proc->waitForFinished(); if(proc->exitStatus()!=QProcess::NormalExit) { *err_msg=QObject::tr("sendmail crashed")+"\r\n"; delete proc; return false; } if(proc->exitCode()!=0) { *err_msg=QObject::tr("sendmail returned non-zero exit code")+ QString().sprintf(": %d [",proc->exitCode())+ QString::fromUtf8(proc->readAllStandardError())+"]\n"; delete proc; return false; } delete proc; *err_msg=QObject::tr("ok"); return true; } bool RDSendMail(QString *err_msg,const QString &subject,const QString &body, const QString &from_addr,const QString &to_addrs, const QString &cc_addrs,const QString &bcc_addrs,bool dry_run) { return RDSendMail(err_msg,subject,body,from_addr, to_addrs.split(",",QString::SkipEmptyParts), cc_addrs.split(",",QString::SkipEmptyParts), bcc_addrs.split(",",QString::SkipEmptyParts), dry_run); }