From 5df79c53745fde5d6c3340a2979b1429cd5892c1 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 8 Oct 2011 20:30:28 +0200 Subject: Initial import of htcd system 1.0 Signed-off-by: Henrik Rydberg --- src/mime/base64.cc | 132 ++++++++++++++++++++++++++++++++++++ src/mime/def.cc | 149 +++++++++++++++++++++++++++++++++++++++++ src/mime/enc.h | 36 ++++++++++ src/mime/mailbox.cc | 137 ++++++++++++++++++++++++++++++++++++++ src/mime/mailbox.h | 60 +++++++++++++++++ src/mime/mime.cc | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mime/mime.h | 99 +++++++++++++++++++++++++++ src/mime/pack.cc | 143 +++++++++++++++++++++++++++++++++++++++ src/mime/pack.h | 48 ++++++++++++++ src/mime/qp.cc | 150 +++++++++++++++++++++++++++++++++++++++++ src/mime/test.cc | 108 ++++++++++++++++++++++++++++++ 11 files changed, 1250 insertions(+) create mode 100644 src/mime/base64.cc create mode 100644 src/mime/def.cc create mode 100644 src/mime/enc.h create mode 100644 src/mime/mailbox.cc create mode 100644 src/mime/mailbox.h create mode 100644 src/mime/mime.cc create mode 100644 src/mime/mime.h create mode 100644 src/mime/pack.cc create mode 100644 src/mime/pack.h create mode 100644 src/mime/qp.cc create mode 100644 src/mime/test.cc (limited to 'src/mime') diff --git a/src/mime/base64.cc b/src/mime/base64.cc new file mode 100644 index 0000000..842bbd3 --- /dev/null +++ b/src/mime/base64.cc @@ -0,0 +1,132 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +static unsigned char char2six[256]={ + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,62,65,65,65,63, + 52,53,54,55,56,57,58,59, + 60,61,65,65,65,64,65,65, + 65, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22, + 23,24,25,65,65,65,65,65, + 65,26,27,28,29,30,31,32, + 33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48, + 49,50,51,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65 +}; +static unsigned char six2char[64]={ + 'A','B','C','D','E','F','G','H', + 'I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X', + 'Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3', + '4','5','6','7','8','9','+','/' +}; +inline void tri2quad(mstream& out,unsigned code,int m=4) +{ + char buf[4]; + buf[3]=six2char[code&63U]; code>>=6; + buf[2]=six2char[code&63U]; code>>=6; + buf[1]=six2char[code&63U]; code>>=6; + buf[0]=six2char[code&63U]; + out.write(buf,m); +} +inline void quad2tri(mstream& out,unsigned code,int m=3) +{ + char buf[3]; + buf[2]=code&255U; code>>=8; + buf[1]=code&255U; code>>=8; + buf[0]=code&255U; + out.write(buf,m); +} + +void encode64(mstream& out,const sref& in) +{ + unsigned m=0,code=0,wrap=0; + for(const char* p=in.begin();p!=in.end();p++) { + code<<=8; + code|=(unsigned char)*p; + if(++m==3) { + tri2quad(out,code); + m=0; + if(++wrap==15) { out< + +const mstring trans_base64="base64"; +const mstring trans_quote="quoted-printable"; +const mstring mime_default="iso-8859-1"; + +void decode64(mstream& out,const sref& in); +void encode64(mstream& out,const sref& in); +void decodeQP(mstream& out,const sref& in); +void encodeQP(mstream& out,const sref& in); +void decodeHeader(mstream& out,mstring& mime,const sref& in); +void encodeHeader(mstream& out,const sref& mime,const sref& in); + +#endif diff --git a/src/mime/mailbox.cc b/src/mime/mailbox.cc new file mode 100644 index 0000000..69f8140 --- /dev/null +++ b/src/mime/mailbox.cc @@ -0,0 +1,137 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +static int FromHead(const sref& body) +{ + sref tag,from,rest=body; + Split(tag,rest); + Split(from,rest); + return tag==from_tag&&htcTime(0,rest)>=0; +} + +///////////////////////////////////////////////////////////////////// + +const mstring nextmsg_tag="\nFrom "; +const mstring sep_tag="--"; + +Message::Message() +{ +} + +int Message::Special(sref line) +{ + line=Rest(line); + from=from0=First(line); + date=Rest(line); + idate=htcTime(0,date); + return idate>=0; +} + +int Message::Handle(const sref& name, + const sref& rawval, + const sref& val, + const rrpile& opts) +{ + mstring mime; + if(Mime::Handle(name,rawval,val,opts)) return 1; + else if(eqn(name,from_tag)) { + swrite sw(from); + decodeHeader(sw,mime,rawval); + } + else if(eqn(name,subject_tag)) { + swrite sw(subject); + decodeHeader(sw,mime,rawval); + } + else if(eqn(name,to_tag)) { + swrite sw(to); + decodeHeader(sw,mime,rawval); + } + else if(eqn(name,msgid_tag)) msgid=rawval; + else if(eqn(name,received_tag)) received.push_back(rawval); + else return 0; + return 1; +} + +void Message::putHead(mstream& out) const +{ + if(from0.nempty()) { out<<"From "< +#include + +const mstring from_tag="From"; +const mstring to_tag="To"; +const mstring subject_tag="Subject"; +const mstring msgid_tag="Message-ID"; +const mstring received_tag="Received"; + +class Message : public Mime { +public: + Message(); + Message(const sref& msg) { Init(msg); } + + mstring from0,from,date,subject,to,msgid; + spile received; + time_t idate; + + void putHead(mstream& out) const; +protected: + int Special(sref line); + int Handle(const sref& name, + const sref& rawval, + const sref& val, + const rrpile& opts); +}; + +typedef msvec Mailbox; + +void AppendMessage(FILE* fp,const sref& msg); +void AppendMessages(FILE* fp,const Mailbox& box); + +int PutMessages(const Mailbox& box,const mstring& path); +int AppendMessages(const Mailbox& box,const mstring& path); + +int GetMessages(Mailbox& box,const mstring& path); + +#endif diff --git a/src/mime/mime.cc b/src/mime/mime.cc new file mode 100644 index 0000000..a7a1884 --- /dev/null +++ b/src/mime/mime.cc @@ -0,0 +1,188 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const charset par_left("([{"),par_right("}])"); + +inline int is_field(const sref& s) { + sref p=s.left_first(':'); + while(cset_spaces.test(p.back())) p=p.popb(); + return p.nempty()&&p.find_of(cset_spaces)<0; +} + +inline int getquoted(const sref& s,char c) { + int i,quote=0,par=0; + for(i=0;ifirst,charset_tag)) cont_type_charset=p->second; + else if(eqn(p->first,name_tag)) cont_type_name=p->second; + else if(eqn(p->first,boundary_tag)) cont_type_boundary=p->second; + } + } + else if(eqn(name,cont_id_tag)) cont_id=val; + else if(eqn(name,cont_desc_tag)) cont_desc=val; + else if(eqn(name,cont_disp_tag)) { + cont_disp=val; + for(rrpile::const_iterator p=opts.begin();p!=opts.end();p++) { + if(eqn(p->first,name_tag)) cont_disp_name=p->second; + else if(eqn(p->first,file_tag)) cont_disp_file=p->second; + } + } + else if(eqn(name,cont_trans_enc_tag)) cont_trans_enc=val; + else if(eqn(name,cont_length_tag)) cont_length=val; + else return 0; + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +void Mime::putHead(mstream& out) const +{ + if(putval(out,mime_version_tag,mime_version)) putend(out); + if(putval(out,cont_type_tag,cont_type)) { + putopt(out,charset_tag,cont_type_charset); + putopt(out,name_tag,cont_type_name); + putopt(out,boundary_tag,cont_type_boundary); + putend(out); + } + if(putval(out,cont_id_tag,cont_id)) putend(out); + if(putval(out,cont_desc_tag,cont_desc)) putend(out); + if(putval(out,cont_disp_tag,cont_disp)) { + putopt(out,name_tag,cont_disp_name); + putopt(out,file_tag,cont_disp_file); + putend(out); + } + if(putval(out,cont_trans_enc_tag,cont_trans_enc)) putend(out); + if(putval(out,cont_length_tag,cont_length)) putend(out); +} + + +/////////////////////////////////////////////////////////////////////////// + +int Mime::Multipart(rpile& list) const +{ + if(cont_type_boundary.empty()) return 0; + mstring bound=sref("--")+cont_type_boundary; + sref rest=body.past_first(bound).past_nl(); + while(rest.nempty()) { + int pos=rest.find(bound); + if(pos>=0) { + sref first=rest.left(pos); + if(first.back()=='\n') { + first=first.popb(); + if(first.back()=='\r') first=first.popb(); + } + list.push_back(first); + rest=rest.right(pos).adv(bound.size()); + if(*rest=='-') rest.clear(); else rest=rest.past_nl(); + } + else { + list.push_back(rest); + rest.clear(); + } + } + return !list.empty(); +} + +void Mime::Pick(const sref& mime) +{ + rpile list; + if(Multipart(list)) { + if(eqn(cont_type,mime_multialt)) { + int pos=0; + for(int i=0;i + +// MIME Headers +const mstring mime_version_tag="MIME-Version"; +const mstring cont_type_tag="Content-Type"; +const mstring cont_trans_enc_tag="Content-Transfer-Encoding"; +const mstring cont_id_tag="Content-ID"; +const mstring cont_desc_tag="Content-Description"; +const mstring cont_disp_tag="Content-Disposition"; +const mstring cont_length_tag="Content-Length"; +// Option headers +const mstring name_tag="name"; +const mstring file_tag="filename"; +const mstring charset_tag="charset"; +const mstring boundary_tag="boundary"; +const mstring path_tag="path"; +// Some Content types +const mstring mime_textplain="text/plain"; +const mstring mime_texthtml="text/html"; +const mstring mime_texthtc="text/x-htc"; +const mstring mime_multialt="multipart/alternative"; + +///////////////////////////////////////////////////////////////// + +const sref* file2mime(const sref& file); + +///////////////////////////////////////////////////////////////// + +class Mime { +public: + sref head,body; + + mstring mime_version; + mstring cont_type,cont_type_charset,cont_type_name,cont_type_boundary; + mstring cont_id; + mstring cont_desc; + mstring cont_disp,cont_disp_name,cont_disp_file; + mstring cont_trans_enc; + mstring cont_length; + + virtual void putHead(mstream& out) const; + + void Init(const sref& in); + + int Multipart(rpile& list) const; + void Pick(const sref& mime); + + Mime(); + Mime(const sref& msg) { Init(msg); } + +protected: + virtual int Special(sref line); + virtual int Handle(const sref& name, + const sref& rawval, + const sref& val, + const rrpile& opts); +}; + +////////////////////////////////////////////////////////////////// + +inline int putval(mstream& out,const sref& tag,const sref& val) { + if(val.nempty()) { out<first); + out.put('='); + Pack(out,p->second); + out.put('&'); + } +} + +/////////////////////////////////////////////////////////////// + +void Unpack(mstream& out,const sref& in) +{ + static const charset tags("%+"); + sref e,p=in; + while(p.nempty()) { + p=p.adv(e=p.left_first_of(tags)); + out< +#include + +// Really mimefunctions, but needed here + +mstream& cashex(mstream& out,unsigned char c); +char hexasc(unsigned char c1,unsigned char c2); + +// Packing means application/x-www-form-urlencoded + +void Unpack(mstream& out,const sref& in); +void Unpack(spile& list,const sref& in); +void Unpack(sspile& list,const sref& in); + +void Pack(mstream& out,const sref& in); +void Pack(mstream& out,const rpile& list); +void Pack(mstream& out,const rrpile& list); + +// CR LF and CRLF business + +const mstring CRLF="\r\n"; + +void CRLF2LF(mstream& out,const sref& in); +void LF2CRLF(mstream& out,const sref& in); + +#endif diff --git a/src/mime/qp.cc b/src/mime/qp.cc new file mode 100644 index 0000000..78dc36f --- /dev/null +++ b/src/mime/qp.cc @@ -0,0 +1,150 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +const charset special("=\"#$\\^`{|}~"); +//const charset special("=!\"#$@[\\]^`{|}~"); +const charset headspecial("_?"); +const charset printable=cset_printable&~special; +const charset printhead=printable&~headspecial; +const mstring beg_tag("=?"),end_tag("?="); +const mstring enc_qp_tag("Q"),enc_64_tag("B"); +const int WRAPAT=76; +const int HEADWRAP=WRAPAT-7; + +void decodeQP(mstream& out,const sref& in) +{ + const char* p=in.begin(); + while(p=WRAPAT) { out.put('=')< +#include +#include +#include + +static fp_stream mout(stdout),merr(stderr); + +static void Show(mstream& out,const Message& msg) +{ + if(msg.cont_type.empty()|| + eqn(msg.cont_type,mime_textplain)|| + eqn(msg.cont_type,mime_texthtml)) { + if(eqn(msg.cont_trans_enc,trans_quote)) { + //decodeQP(out,msg.body); + mswrite tmp; + decodeQP(tmp,msg.body); + encodeQP(out,tmp.str()); + } + else { + //out< [index]\n"; + return 1; + } + Mailbox box; + GetMessages(box,argv[1]); + merr<<"Found "<2) { + Message msg(box[atoi(argv[2])]); + //msg.Pick(mime_textplain); + + mswrite tmp; + encodeHeader(tmp,mime_default,msg.subject); + msg.subject=tmp.str(); + + msg.putHead(mout); + mout<<"-----------------------------------------\n"; + rpile part; + if(msg.Multipart(part)) { + for(int i=0;i\n"; + return 1; + } + mstring buffer; buffer.load(argv[1]); + merr<