diff options
Diffstat (limited to 'src/mime')
| -rw-r--r-- | src/mime/base64.cc | 132 | ||||
| -rw-r--r-- | src/mime/def.cc | 149 | ||||
| -rw-r--r-- | src/mime/enc.h | 36 | ||||
| -rw-r--r-- | src/mime/mailbox.cc | 137 | ||||
| -rw-r--r-- | src/mime/mailbox.h | 60 | ||||
| -rw-r--r-- | src/mime/mime.cc | 188 | ||||
| -rw-r--r-- | src/mime/mime.h | 99 | ||||
| -rw-r--r-- | src/mime/pack.cc | 143 | ||||
| -rw-r--r-- | src/mime/pack.h | 48 | ||||
| -rw-r--r-- | src/mime/qp.cc | 150 | ||||
| -rw-r--r-- | src/mime/test.cc | 108 |
11 files changed, 1250 insertions, 0 deletions
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 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/enc.h> | ||
| 21 | |||
| 22 | static unsigned char char2six[256]={ | ||
| 23 | 65,65,65,65,65,65,65,65, | ||
| 24 | 65,65,65,65,65,65,65,65, | ||
| 25 | 65,65,65,65,65,65,65,65, | ||
| 26 | 65,65,65,65,65,65,65,65, | ||
| 27 | 65,65,65,65,65,65,65,65, | ||
| 28 | 65,65,65,62,65,65,65,63, | ||
| 29 | 52,53,54,55,56,57,58,59, | ||
| 30 | 60,61,65,65,65,64,65,65, | ||
| 31 | 65, 0, 1, 2, 3, 4, 5, 6, | ||
| 32 | 7, 8, 9,10,11,12,13,14, | ||
| 33 | 15,16,17,18,19,20,21,22, | ||
| 34 | 23,24,25,65,65,65,65,65, | ||
| 35 | 65,26,27,28,29,30,31,32, | ||
| 36 | 33,34,35,36,37,38,39,40, | ||
| 37 | 41,42,43,44,45,46,47,48, | ||
| 38 | 49,50,51,65,65,65,65,65, | ||
| 39 | 65,65,65,65,65,65,65,65, | ||
| 40 | 65,65,65,65,65,65,65,65, | ||
| 41 | 65,65,65,65,65,65,65,65, | ||
| 42 | 65,65,65,65,65,65,65,65, | ||
| 43 | 65,65,65,65,65,65,65,65, | ||
| 44 | 65,65,65,65,65,65,65,65, | ||
| 45 | 65,65,65,65,65,65,65,65, | ||
| 46 | 65,65,65,65,65,65,65,65, | ||
| 47 | 65,65,65,65,65,65,65,65, | ||
| 48 | 65,65,65,65,65,65,65,65, | ||
| 49 | 65,65,65,65,65,65,65,65, | ||
| 50 | 65,65,65,65,65,65,65,65, | ||
| 51 | 65,65,65,65,65,65,65,65, | ||
| 52 | 65,65,65,65,65,65,65,65, | ||
| 53 | 65,65,65,65,65,65,65,65, | ||
| 54 | 65,65,65,65,65,65,65,65 | ||
| 55 | }; | ||
| 56 | static unsigned char six2char[64]={ | ||
| 57 | 'A','B','C','D','E','F','G','H', | ||
| 58 | 'I','J','K','L','M','N','O','P', | ||
| 59 | 'Q','R','S','T','U','V','W','X', | ||
| 60 | 'Y','Z','a','b','c','d','e','f', | ||
| 61 | 'g','h','i','j','k','l','m','n', | ||
| 62 | 'o','p','q','r','s','t','u','v', | ||
| 63 | 'w','x','y','z','0','1','2','3', | ||
| 64 | '4','5','6','7','8','9','+','/' | ||
| 65 | }; | ||
| 66 | inline void tri2quad(mstream& out,unsigned code,int m=4) | ||
| 67 | { | ||
| 68 | char buf[4]; | ||
| 69 | buf[3]=six2char[code&63U]; code>>=6; | ||
| 70 | buf[2]=six2char[code&63U]; code>>=6; | ||
| 71 | buf[1]=six2char[code&63U]; code>>=6; | ||
| 72 | buf[0]=six2char[code&63U]; | ||
| 73 | out.write(buf,m); | ||
| 74 | } | ||
| 75 | inline void quad2tri(mstream& out,unsigned code,int m=3) | ||
| 76 | { | ||
| 77 | char buf[3]; | ||
| 78 | buf[2]=code&255U; code>>=8; | ||
| 79 | buf[1]=code&255U; code>>=8; | ||
| 80 | buf[0]=code&255U; | ||
| 81 | out.write(buf,m); | ||
| 82 | } | ||
| 83 | |||
| 84 | void encode64(mstream& out,const sref& in) | ||
| 85 | { | ||
| 86 | unsigned m=0,code=0,wrap=0; | ||
| 87 | for(const char* p=in.begin();p!=in.end();p++) { | ||
| 88 | code<<=8; | ||
| 89 | code|=(unsigned char)*p; | ||
| 90 | if(++m==3) { | ||
| 91 | tri2quad(out,code); | ||
| 92 | m=0; | ||
| 93 | if(++wrap==15) { out<<CRLF; wrap=0; } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | if(m==1) { | ||
| 97 | code<<=16; | ||
| 98 | tri2quad(out,code,2); | ||
| 99 | out<<"=="; | ||
| 100 | if(++wrap==15) { out<<CRLF; wrap=0; } | ||
| 101 | } | ||
| 102 | else if(m==2) { | ||
| 103 | code<<=8; | ||
| 104 | tri2quad(out,code,3); | ||
| 105 | out.put('='); | ||
| 106 | if(++wrap==15) { out<<CRLF; wrap=0; } | ||
| 107 | } | ||
| 108 | if(wrap>0) out<<CRLF; | ||
| 109 | } | ||
| 110 | |||
| 111 | void decode64(mstream& out,const sref& in) | ||
| 112 | { | ||
| 113 | unsigned m=0,code=0,six=0; | ||
| 114 | for(const char* p=in.begin();p!=in.end();p++) { | ||
| 115 | six=char2six[(unsigned char)*p]; | ||
| 116 | if(six>=64) continue; | ||
| 117 | code<<=6; | ||
| 118 | code|=six; | ||
| 119 | if(++m==4) { | ||
| 120 | quad2tri(out,code); | ||
| 121 | m=0; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | if(m==2) { | ||
| 125 | code<<=12; | ||
| 126 | quad2tri(out,code,1); | ||
| 127 | } | ||
| 128 | else if(m==3) { | ||
| 129 | code<<=6; | ||
| 130 | quad2tri(out,code,2); | ||
| 131 | } | ||
| 132 | } | ||
diff --git a/src/mime/def.cc b/src/mime/def.cc new file mode 100644 index 0000000..0a692cd --- /dev/null +++ b/src/mime/def.cc | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/mime.h> | ||
| 21 | #include <mt/msmap.h> | ||
| 22 | |||
| 23 | struct table_t { char ext[16],name[64]; }; | ||
| 24 | |||
| 25 | static table_t table[]={ | ||
| 26 | {"ai","application/postscript"}, | ||
| 27 | {"aif","audio/x-aiff"}, | ||
| 28 | {"aifc","audio/x-aiff"}, | ||
| 29 | {"aiff","audio/x-aiff"}, | ||
| 30 | {"au","audio/basic"}, | ||
| 31 | {"avi","video/x-msvideo"}, | ||
| 32 | {"bcpio","application/x-bcpio"}, | ||
| 33 | {"bin","application/octet-stream"}, | ||
| 34 | {"cdf","application/x-netcdf"}, | ||
| 35 | {"class","application/octet-stream"}, | ||
| 36 | {"cpio","application/x-cpio"}, | ||
| 37 | {"cpt","application/mac-compactpro"}, | ||
| 38 | {"csh","application/x-csh"}, | ||
| 39 | {"css","text/css"}, | ||
| 40 | {"dcr","application/x-director"}, | ||
| 41 | {"dir","application/x-director"}, | ||
| 42 | {"dms","application/octet-stream"}, | ||
| 43 | {"doc","application/msword"}, | ||
| 44 | {"dvi","application/x-dvi"}, | ||
| 45 | {"dxr","application/x-director"}, | ||
| 46 | {"eps","application/postscript"}, | ||
| 47 | {"etx","text/x-setext"}, | ||
| 48 | {"exe","application/octet-stream"}, | ||
| 49 | {"gif","image/gif"}, | ||
| 50 | {"gtar","application/x-gtar"}, | ||
| 51 | {"gz","application/x-gzip"}, | ||
| 52 | {"hdf","application/x-hdf"}, | ||
| 53 | {"hqx","application/mac-binhex40"}, | ||
| 54 | {"htc","text/x-htc"}, | ||
| 55 | {"hts","text/plain"}, | ||
| 56 | {"htx","text/x-htx"}, | ||
| 57 | {"htm","text/html"}, | ||
| 58 | {"html","text/html"}, | ||
| 59 | {"ice","x-conference/x-cooltalk"}, | ||
| 60 | {"ief","image/ief"}, | ||
| 61 | {"jpe","image/jpeg"}, | ||
| 62 | {"jpeg","image/jpeg"}, | ||
| 63 | {"jpg","image/jpeg"}, | ||
| 64 | {"kar","audio/midi"}, | ||
| 65 | {"latex","application/x-latex"}, | ||
| 66 | {"lha","application/octet-stream"}, | ||
| 67 | {"lzh","application/octet-stream"}, | ||
| 68 | {"man","application/x-troff-man"}, | ||
| 69 | {"me","application/x-troff-me"}, | ||
| 70 | {"mid","audio/midi"}, | ||
| 71 | {"midi","audio/midi"}, | ||
| 72 | {"mif","application/x-mif"}, | ||
| 73 | {"mov","video/quicktime"}, | ||
| 74 | {"movie","video/x-sgi-movie"}, | ||
| 75 | {"mp2","audio/mpeg"}, | ||
| 76 | {"mp3","audio/mpeg"}, | ||
| 77 | {"mpe","video/mpeg"}, | ||
| 78 | {"mpeg","video/mpeg"}, | ||
| 79 | {"mpg","video/mpeg"}, | ||
| 80 | {"mpga","audio/mpeg"}, | ||
| 81 | {"ms","application/x-troff-ms"}, | ||
| 82 | {"nc","application/x-netcdf"}, | ||
| 83 | {"oda","application/oda"}, | ||
| 84 | {"pbm","image/x-portable-bitmap"}, | ||
| 85 | {"pdb","chemical/x-pdb"}, | ||
| 86 | {"pdf","application/pdf"}, | ||
| 87 | {"pgm","image/x-portable-graymap"}, | ||
| 88 | {"png","image/png"}, | ||
| 89 | {"pnm","image/x-portable-anymap"}, | ||
| 90 | {"ppm","image/x-portable-pixmap"}, | ||
| 91 | {"ppt","application/powerpoint"}, | ||
| 92 | {"ps","application/postscript"}, | ||
| 93 | {"qt","video/quicktime"}, | ||
| 94 | {"ra","audio/x-realaudio"}, | ||
| 95 | {"ram","audio/x-pn-realaudio"}, | ||
| 96 | {"ras","image/x-cmu-raster"}, | ||
| 97 | {"rgb","image/x-rgb"}, | ||
| 98 | {"roff","application/x-troff"}, | ||
| 99 | {"rpm","audio/x-pn-realaudio-plugin"}, | ||
| 100 | {"rtf","application/rtf"}, | ||
| 101 | {"rtx","text/richtext"}, | ||
| 102 | {"sgm","text/x-sgml"}, | ||
| 103 | {"sgml","text/x-sgml"}, | ||
| 104 | {"sh","application/x-sh"}, | ||
| 105 | {"shar","application/x-shar"}, | ||
| 106 | {"sit","application/x-stuffit"}, | ||
| 107 | {"skd","application/x-koan"}, | ||
| 108 | {"skm","application/x-koan"}, | ||
| 109 | {"skp","application/x-koan"}, | ||
| 110 | {"skt","application/x-koan"}, | ||
| 111 | {"snd","audio/basic"}, | ||
| 112 | {"src","application/x-wais-source"}, | ||
| 113 | {"sv4cpio","application/x-sv4cpio"}, | ||
| 114 | {"sv4crc","application/x-sv4crc"}, | ||
| 115 | {"t","application/x-troff"}, | ||
| 116 | {"tar","application/x-tar"}, | ||
| 117 | {"tcl","application/x-tcl"}, | ||
| 118 | {"tex","application/x-tex"}, | ||
| 119 | {"texi","application/x-texinfo"}, | ||
| 120 | {"texinfo","application/x-texinfo"}, | ||
| 121 | {"tif","image/tiff"}, | ||
| 122 | {"tiff","image/tiff"}, | ||
| 123 | {"tr","application/x-troff"}, | ||
| 124 | {"tsv","text/tab-separated-values"}, | ||
| 125 | {"txt","text/plain"}, | ||
| 126 | {"ustar","application/x-ustar"}, | ||
| 127 | {"vcd","application/x-cdlink"}, | ||
| 128 | {"vrml","x-world/x-vrml"}, | ||
| 129 | {"wav","audio/x-wav"}, | ||
| 130 | {"wrl","x-world/x-vrml"}, | ||
| 131 | {"xbm","image/x-xbitmap"}, | ||
| 132 | {"xpm","image/x-xpixmap"}, | ||
| 133 | {"xwd","image/x-xwindowdump"}, | ||
| 134 | {"xyz","chemical/x-pdb"}, | ||
| 135 | {"zip","application/zip"}, | ||
| 136 | {"",""} | ||
| 137 | }; | ||
| 138 | |||
| 139 | const sref* file2mime(const sref& file) | ||
| 140 | { | ||
| 141 | static rrmap mime; | ||
| 142 | if(mime.empty()) { | ||
| 143 | for(table_t* p=table;*p->ext;p++) mime.add(sref(p->ext),sref(p->name)); | ||
| 144 | } | ||
| 145 | mstring path=file.past_last('.'); | ||
| 146 | path.tolower(); | ||
| 147 | if(path.nempty()) return mime.get(path); | ||
| 148 | return 0; | ||
| 149 | } | ||
diff --git a/src/mime/enc.h b/src/mime/enc.h new file mode 100644 index 0000000..a6ec57a --- /dev/null +++ b/src/mime/enc.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef ENCMIMEH | ||
| 21 | #define ENCMIMEH | ||
| 22 | |||
| 23 | #include <mime/pack.h> | ||
| 24 | |||
| 25 | const mstring trans_base64="base64"; | ||
| 26 | const mstring trans_quote="quoted-printable"; | ||
| 27 | const mstring mime_default="iso-8859-1"; | ||
| 28 | |||
| 29 | void decode64(mstream& out,const sref& in); | ||
| 30 | void encode64(mstream& out,const sref& in); | ||
| 31 | void decodeQP(mstream& out,const sref& in); | ||
| 32 | void encodeQP(mstream& out,const sref& in); | ||
| 33 | void decodeHeader(mstream& out,mstring& mime,const sref& in); | ||
| 34 | void encodeHeader(mstream& out,const sref& mime,const sref& in); | ||
| 35 | |||
| 36 | #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 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/mailbox.h> | ||
| 21 | |||
| 22 | static int FromHead(const sref& body) | ||
| 23 | { | ||
| 24 | sref tag,from,rest=body; | ||
| 25 | Split(tag,rest); | ||
| 26 | Split(from,rest); | ||
| 27 | return tag==from_tag&&htcTime(0,rest)>=0; | ||
| 28 | } | ||
| 29 | |||
| 30 | ///////////////////////////////////////////////////////////////////// | ||
| 31 | |||
| 32 | const mstring nextmsg_tag="\nFrom "; | ||
| 33 | const mstring sep_tag="--"; | ||
| 34 | |||
| 35 | Message::Message() | ||
| 36 | { | ||
| 37 | } | ||
| 38 | |||
| 39 | int Message::Special(sref line) | ||
| 40 | { | ||
| 41 | line=Rest(line); | ||
| 42 | from=from0=First(line); | ||
| 43 | date=Rest(line); | ||
| 44 | idate=htcTime(0,date); | ||
| 45 | return idate>=0; | ||
| 46 | } | ||
| 47 | |||
| 48 | int Message::Handle(const sref& name, | ||
| 49 | const sref& rawval, | ||
| 50 | const sref& val, | ||
| 51 | const rrpile& opts) | ||
| 52 | { | ||
| 53 | mstring mime; | ||
| 54 | if(Mime::Handle(name,rawval,val,opts)) return 1; | ||
| 55 | else if(eqn(name,from_tag)) { | ||
| 56 | swrite sw(from); | ||
| 57 | decodeHeader(sw,mime,rawval); | ||
| 58 | } | ||
| 59 | else if(eqn(name,subject_tag)) { | ||
| 60 | swrite sw(subject); | ||
| 61 | decodeHeader(sw,mime,rawval); | ||
| 62 | } | ||
| 63 | else if(eqn(name,to_tag)) { | ||
| 64 | swrite sw(to); | ||
| 65 | decodeHeader(sw,mime,rawval); | ||
| 66 | } | ||
| 67 | else if(eqn(name,msgid_tag)) msgid=rawval; | ||
| 68 | else if(eqn(name,received_tag)) received.push_back(rawval); | ||
| 69 | else return 0; | ||
| 70 | return 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | void Message::putHead(mstream& out) const | ||
| 74 | { | ||
| 75 | if(from0.nempty()) { out<<"From "<<from0<<" "<<date<<"\r\n"; } | ||
| 76 | if(putval(out,from_tag,from)) putend(out); | ||
| 77 | if(putval(out,subject_tag,subject)) putend(out); | ||
| 78 | if(putval(out,to_tag,to)) putend(out); | ||
| 79 | if(putval(out,msgid_tag,msgid)) putend(out); | ||
| 80 | for(spile::const_iterator p=received.begin();p!=received.end();p++) | ||
| 81 | if(putval(out,received_tag,*p)) putend(out); | ||
| 82 | Mime::putHead(out); | ||
| 83 | } | ||
| 84 | |||
| 85 | /////////////////////////////////////////////////////////////// | ||
| 86 | |||
| 87 | void AppendMessage(FILE* fp,const sref& msg) | ||
| 88 | { | ||
| 89 | fwrite(msg.data(),1,msg.size(),fp); | ||
| 90 | } | ||
| 91 | |||
| 92 | void AppendMessages(FILE* fp,const Mailbox& box) | ||
| 93 | { | ||
| 94 | for(int i=0;i<box.size();i++) AppendMessage(fp,box[i]); | ||
| 95 | } | ||
| 96 | |||
| 97 | int PutMessages(const Mailbox& box,const mstring& path) | ||
| 98 | { | ||
| 99 | FILE* fp=fopen(path.c_str(),"w+"); | ||
| 100 | if(!fp) return 0; | ||
| 101 | AppendMessages(fp,box); | ||
| 102 | return fclose(fp)==0; | ||
| 103 | } | ||
| 104 | |||
| 105 | int AppendMessages(const Mailbox& box,const mstring& path) | ||
| 106 | { | ||
| 107 | FILE* fp=fopen(path.c_str(),"a+"); | ||
| 108 | if(!fp) return 0; | ||
| 109 | AppendMessages(fp,box); | ||
| 110 | return fclose(fp)==0; | ||
| 111 | } | ||
| 112 | |||
| 113 | /////////////////////////////////////////////////////////////// | ||
| 114 | |||
| 115 | int GetMessages(Mailbox& box,const mstring& path) | ||
| 116 | { | ||
| 117 | mstring buffer; if(buffer.load(path)<0) return -1; | ||
| 118 | sref next,rest=buffer; | ||
| 119 | int old=box.size(); | ||
| 120 | while(rest.nempty()) { | ||
| 121 | Message msg(rest); | ||
| 122 | if(msg.from0.empty()) break; // should not happen, I guess | ||
| 123 | |||
| 124 | if(msg.cont_length.nempty()) | ||
| 125 | next=msg.body.right(atoi(msg.cont_length)); | ||
| 126 | else if(msg.cont_type_boundary.nempty()) | ||
| 127 | next=msg.body.past_first(sep_tag+msg.cont_type_boundary+sep_tag).right_first(nextmsg_tag).popf(); | ||
| 128 | else | ||
| 129 | next=rest.right_first(nextmsg_tag).popf(); | ||
| 130 | |||
| 131 | box.push_back(rest.left(next-rest)); | ||
| 132 | |||
| 133 | rest=next.right_first_not_of(cset_ws); | ||
| 134 | while(rest.nempty()&&!FromHead(rest)) rest=rest.right_first(nextmsg_tag).popf(); | ||
| 135 | } | ||
| 136 | return box.size()-old; | ||
| 137 | } | ||
diff --git a/src/mime/mailbox.h b/src/mime/mailbox.h new file mode 100644 index 0000000..3e5838c --- /dev/null +++ b/src/mime/mailbox.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef MAILBOXH | ||
| 21 | #define MAILBOXH | ||
| 22 | |||
| 23 | #include <mime/mime.h> | ||
| 24 | #include <mt/dates.h> | ||
| 25 | |||
| 26 | const mstring from_tag="From"; | ||
| 27 | const mstring to_tag="To"; | ||
| 28 | const mstring subject_tag="Subject"; | ||
| 29 | const mstring msgid_tag="Message-ID"; | ||
| 30 | const mstring received_tag="Received"; | ||
| 31 | |||
| 32 | class Message : public Mime { | ||
| 33 | public: | ||
| 34 | Message(); | ||
| 35 | Message(const sref& msg) { Init(msg); } | ||
| 36 | |||
| 37 | mstring from0,from,date,subject,to,msgid; | ||
| 38 | spile received; | ||
| 39 | time_t idate; | ||
| 40 | |||
| 41 | void putHead(mstream& out) const; | ||
| 42 | protected: | ||
| 43 | int Special(sref line); | ||
| 44 | int Handle(const sref& name, | ||
| 45 | const sref& rawval, | ||
| 46 | const sref& val, | ||
| 47 | const rrpile& opts); | ||
| 48 | }; | ||
| 49 | |||
| 50 | typedef msvec<mstring> Mailbox; | ||
| 51 | |||
| 52 | void AppendMessage(FILE* fp,const sref& msg); | ||
| 53 | void AppendMessages(FILE* fp,const Mailbox& box); | ||
| 54 | |||
| 55 | int PutMessages(const Mailbox& box,const mstring& path); | ||
| 56 | int AppendMessages(const Mailbox& box,const mstring& path); | ||
| 57 | |||
| 58 | int GetMessages(Mailbox& box,const mstring& path); | ||
| 59 | |||
| 60 | #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 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/mime.h> | ||
| 21 | |||
| 22 | const charset par_left("([{"),par_right("}])"); | ||
| 23 | |||
| 24 | inline int is_field(const sref& s) { | ||
| 25 | sref p=s.left_first(':'); | ||
| 26 | while(cset_spaces.test(p.back())) p=p.popb(); | ||
| 27 | return p.nempty()&&p.find_of(cset_spaces)<0; | ||
| 28 | } | ||
| 29 | |||
| 30 | inline int getquoted(const sref& s,char c) { | ||
| 31 | int i,quote=0,par=0; | ||
| 32 | for(i=0;i<s.size();i++) { | ||
| 33 | if(s[i]=='\"') quote=!quote; | ||
| 34 | else if(par_left.test(s[i])) par++; | ||
| 35 | else if(par_right.test(s[i])) par--; | ||
| 36 | else if(s[i]==c&&!quote&&!par) break; | ||
| 37 | } | ||
| 38 | return i; | ||
| 39 | } | ||
| 40 | |||
| 41 | void Mime::Init(const sref& message) | ||
| 42 | { | ||
| 43 | mstring line; | ||
| 44 | rrpile pile; | ||
| 45 | sref first; | ||
| 46 | head=body=message; | ||
| 47 | while(Splitln(first,body)) { | ||
| 48 | if(first.empty()) break; | ||
| 49 | if(!is_field(first)) Special(first); | ||
| 50 | else { | ||
| 51 | line=first; | ||
| 52 | while(cset_spaces.test(*body)) { | ||
| 53 | Splitln(first,body); | ||
| 54 | line.append(1,' '); | ||
| 55 | line+=first.right_first_not_of(cset_spaces); | ||
| 56 | } | ||
| 57 | sref opt=line; | ||
| 58 | int col=opt.find(':'); | ||
| 59 | sref name=Trim(opt.left(col),cset_quotes); | ||
| 60 | opt=opt.adv(col).popf(); | ||
| 61 | sref rawval=Trim(opt); | ||
| 62 | int semi=getquoted(opt,';'); | ||
| 63 | sref val=Trim(opt.left(semi),cset_quotes); | ||
| 64 | if(getquoted(val,'=')<val.size()) val.clear(); | ||
| 65 | else opt=opt.adv(semi).popf(); | ||
| 66 | pile.clear(); | ||
| 67 | while(opt.nempty()) { | ||
| 68 | sref optname=opt.left(getquoted(opt,'=')); | ||
| 69 | opt=opt.adv(optname).popf(); | ||
| 70 | semi=getquoted(opt,';'); | ||
| 71 | sref optval=opt.left(semi); | ||
| 72 | opt=opt.adv(semi).popf(); | ||
| 73 | optname=Trim(optname,cset_quotes); | ||
| 74 | optval=Trim(optval,cset_quotes); | ||
| 75 | if(optname.nempty()) pile.push_back(rrstring(optname,optval)); | ||
| 76 | } | ||
| 77 | Handle(name,rawval,val,pile); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | head=head.left(body-head); | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | /////////////////////////////////////////////////////////////////////////// | ||
| 85 | |||
| 86 | Mime::Mime() | ||
| 87 | { | ||
| 88 | mime_version="1.0"; | ||
| 89 | } | ||
| 90 | |||
| 91 | int Mime::Special(sref line) | ||
| 92 | { | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | int Mime::Handle(const sref& name, | ||
| 97 | const sref& rawval, | ||
| 98 | const sref& val, | ||
| 99 | const rrpile& opts) { | ||
| 100 | if(eqn(name,mime_version_tag)) mime_version=val; | ||
| 101 | else if(eqn(name,cont_type_tag)) { | ||
| 102 | (cont_type=val).tolower(); | ||
| 103 | for(rrpile::const_iterator p=opts.begin();p!=opts.end();p++) { | ||
| 104 | if(eqn(p->first,charset_tag)) cont_type_charset=p->second; | ||
| 105 | else if(eqn(p->first,name_tag)) cont_type_name=p->second; | ||
| 106 | else if(eqn(p->first,boundary_tag)) cont_type_boundary=p->second; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | else if(eqn(name,cont_id_tag)) cont_id=val; | ||
| 110 | else if(eqn(name,cont_desc_tag)) cont_desc=val; | ||
| 111 | else if(eqn(name,cont_disp_tag)) { | ||
| 112 | cont_disp=val; | ||
| 113 | for(rrpile::const_iterator p=opts.begin();p!=opts.end();p++) { | ||
| 114 | if(eqn(p->first,name_tag)) cont_disp_name=p->second; | ||
| 115 | else if(eqn(p->first,file_tag)) cont_disp_file=p->second; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | else if(eqn(name,cont_trans_enc_tag)) cont_trans_enc=val; | ||
| 119 | else if(eqn(name,cont_length_tag)) cont_length=val; | ||
| 120 | else return 0; | ||
| 121 | return 1; | ||
| 122 | } | ||
| 123 | |||
| 124 | /////////////////////////////////////////////////////////////////////////// | ||
| 125 | |||
| 126 | void Mime::putHead(mstream& out) const | ||
| 127 | { | ||
| 128 | if(putval(out,mime_version_tag,mime_version)) putend(out); | ||
| 129 | if(putval(out,cont_type_tag,cont_type)) { | ||
| 130 | putopt(out,charset_tag,cont_type_charset); | ||
| 131 | putopt(out,name_tag,cont_type_name); | ||
| 132 | putopt(out,boundary_tag,cont_type_boundary); | ||
| 133 | putend(out); | ||
| 134 | } | ||
| 135 | if(putval(out,cont_id_tag,cont_id)) putend(out); | ||
| 136 | if(putval(out,cont_desc_tag,cont_desc)) putend(out); | ||
| 137 | if(putval(out,cont_disp_tag,cont_disp)) { | ||
| 138 | putopt(out,name_tag,cont_disp_name); | ||
| 139 | putopt(out,file_tag,cont_disp_file); | ||
| 140 | putend(out); | ||
| 141 | } | ||
| 142 | if(putval(out,cont_trans_enc_tag,cont_trans_enc)) putend(out); | ||
| 143 | if(putval(out,cont_length_tag,cont_length)) putend(out); | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | /////////////////////////////////////////////////////////////////////////// | ||
| 148 | |||
| 149 | int Mime::Multipart(rpile& list) const | ||
| 150 | { | ||
| 151 | if(cont_type_boundary.empty()) return 0; | ||
| 152 | mstring bound=sref("--")+cont_type_boundary; | ||
| 153 | sref rest=body.past_first(bound).past_nl(); | ||
| 154 | while(rest.nempty()) { | ||
| 155 | int pos=rest.find(bound); | ||
| 156 | if(pos>=0) { | ||
| 157 | sref first=rest.left(pos); | ||
| 158 | if(first.back()=='\n') { | ||
| 159 | first=first.popb(); | ||
| 160 | if(first.back()=='\r') first=first.popb(); | ||
| 161 | } | ||
| 162 | list.push_back(first); | ||
| 163 | rest=rest.right(pos).adv(bound.size()); | ||
| 164 | if(*rest=='-') rest.clear(); else rest=rest.past_nl(); | ||
| 165 | } | ||
| 166 | else { | ||
| 167 | list.push_back(rest); | ||
| 168 | rest.clear(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | return !list.empty(); | ||
| 172 | } | ||
| 173 | |||
| 174 | void Mime::Pick(const sref& mime) | ||
| 175 | { | ||
| 176 | rpile list; | ||
| 177 | if(Multipart(list)) { | ||
| 178 | if(eqn(cont_type,mime_multialt)) { | ||
| 179 | int pos=0; | ||
| 180 | for(int i=0;i<list.size();i++) { | ||
| 181 | Mime msg(list[i]); | ||
| 182 | if(eqn(msg.cont_type,mime)) { pos=i; break; } | ||
| 183 | } | ||
| 184 | Init(list[pos]); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
diff --git a/src/mime/mime.h b/src/mime/mime.h new file mode 100644 index 0000000..fb2ae0f --- /dev/null +++ b/src/mime/mime.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef MIMEH | ||
| 21 | #define MIMEH | ||
| 22 | |||
| 23 | #include <mime/enc.h> | ||
| 24 | |||
| 25 | // MIME Headers | ||
| 26 | const mstring mime_version_tag="MIME-Version"; | ||
| 27 | const mstring cont_type_tag="Content-Type"; | ||
| 28 | const mstring cont_trans_enc_tag="Content-Transfer-Encoding"; | ||
| 29 | const mstring cont_id_tag="Content-ID"; | ||
| 30 | const mstring cont_desc_tag="Content-Description"; | ||
| 31 | const mstring cont_disp_tag="Content-Disposition"; | ||
| 32 | const mstring cont_length_tag="Content-Length"; | ||
| 33 | // Option headers | ||
| 34 | const mstring name_tag="name"; | ||
| 35 | const mstring file_tag="filename"; | ||
| 36 | const mstring charset_tag="charset"; | ||
| 37 | const mstring boundary_tag="boundary"; | ||
| 38 | const mstring path_tag="path"; | ||
| 39 | // Some Content types | ||
| 40 | const mstring mime_textplain="text/plain"; | ||
| 41 | const mstring mime_texthtml="text/html"; | ||
| 42 | const mstring mime_texthtc="text/x-htc"; | ||
| 43 | const mstring mime_multialt="multipart/alternative"; | ||
| 44 | |||
| 45 | ///////////////////////////////////////////////////////////////// | ||
| 46 | |||
| 47 | const sref* file2mime(const sref& file); | ||
| 48 | |||
| 49 | ///////////////////////////////////////////////////////////////// | ||
| 50 | |||
| 51 | class Mime { | ||
| 52 | public: | ||
| 53 | sref head,body; | ||
| 54 | |||
| 55 | mstring mime_version; | ||
| 56 | mstring cont_type,cont_type_charset,cont_type_name,cont_type_boundary; | ||
| 57 | mstring cont_id; | ||
| 58 | mstring cont_desc; | ||
| 59 | mstring cont_disp,cont_disp_name,cont_disp_file; | ||
| 60 | mstring cont_trans_enc; | ||
| 61 | mstring cont_length; | ||
| 62 | |||
| 63 | virtual void putHead(mstream& out) const; | ||
| 64 | |||
| 65 | void Init(const sref& in); | ||
| 66 | |||
| 67 | int Multipart(rpile& list) const; | ||
| 68 | void Pick(const sref& mime); | ||
| 69 | |||
| 70 | Mime(); | ||
| 71 | Mime(const sref& msg) { Init(msg); } | ||
| 72 | |||
| 73 | protected: | ||
| 74 | virtual int Special(sref line); | ||
| 75 | virtual int Handle(const sref& name, | ||
| 76 | const sref& rawval, | ||
| 77 | const sref& val, | ||
| 78 | const rrpile& opts); | ||
| 79 | }; | ||
| 80 | |||
| 81 | ////////////////////////////////////////////////////////////////// | ||
| 82 | |||
| 83 | inline int putval(mstream& out,const sref& tag,const sref& val) { | ||
| 84 | if(val.nempty()) { out<<tag<<": "<<val; return 1; } else return 0; | ||
| 85 | } | ||
| 86 | inline void putopt(mstream& out,const sref& tag,const sref& val) { | ||
| 87 | if(val.nempty()) out<<"; "<<tag<<"=\""<<val<<"\""; | ||
| 88 | } | ||
| 89 | inline int putopt1(mstream& out,const sref& tag,const sref& val) { | ||
| 90 | if(val.nempty()) { out<<tag<<"=\""<<val<<"\""; return 1; } else return 0; | ||
| 91 | } | ||
| 92 | inline int putopt2(mstream& out,const sref& tag,const sref& val) { | ||
| 93 | if(val.nempty()) { out<<tag<<"="<<val; return 1; } else return 0; | ||
| 94 | } | ||
| 95 | inline void putend(mstream& out) { out<<CRLF; } | ||
| 96 | |||
| 97 | ////////////////////////////////////////////////////////////////// | ||
| 98 | |||
| 99 | #endif | ||
diff --git a/src/mime/pack.cc b/src/mime/pack.cc new file mode 100644 index 0000000..78fde26 --- /dev/null +++ b/src/mime/pack.cc | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/pack.h> | ||
| 21 | |||
| 22 | const char hex2char[16]={ | ||
| 23 | '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' | ||
| 24 | }; | ||
| 25 | const unsigned char2hex[256]={ | ||
| 26 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, | ||
| 28 | 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 29 | 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
| 34 | }; | ||
| 35 | |||
| 36 | mstream& cashex(mstream& out,unsigned char c) { | ||
| 37 | return out.put(hex2char[c>>4]).put(hex2char[c&15]); | ||
| 38 | } | ||
| 39 | char hexasc(unsigned char c1,unsigned char c2) { | ||
| 40 | return ((char2hex[c1]<<4)|char2hex[c2]); | ||
| 41 | } | ||
| 42 | |||
| 43 | void Pack(mstream& out,const sref& s) | ||
| 44 | { | ||
| 45 | static const charset escaped("&=%+\"'? "); | ||
| 46 | static const charset conv=~cset_printable|escaped; | ||
| 47 | sref q,p=s; | ||
| 48 | while(p.nempty()) { | ||
| 49 | p=p.adv(q=p.left_first_of(conv)); | ||
| 50 | out<<q; | ||
| 51 | while(conv.test(p.front())) { | ||
| 52 | char c=*p; p=p.popf(); | ||
| 53 | if(c==' ') out.put('+'); | ||
| 54 | else { | ||
| 55 | out.put('%'); | ||
| 56 | cashex(out,c); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | void Pack(mstream& out,const rpile& list) | ||
| 63 | { | ||
| 64 | for(rpile::const_iterator p=list.begin();p!=list.end();++p) { | ||
| 65 | Pack(out,*p); | ||
| 66 | out.put('&'); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | void Pack(mstream& out,const rrpile& list) | ||
| 71 | { | ||
| 72 | for(rrpile::const_iterator p=list.begin();p!=list.end();++p) { | ||
| 73 | Pack(out,p->first); | ||
| 74 | out.put('='); | ||
| 75 | Pack(out,p->second); | ||
| 76 | out.put('&'); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | /////////////////////////////////////////////////////////////// | ||
| 81 | |||
| 82 | void Unpack(mstream& out,const sref& in) | ||
| 83 | { | ||
| 84 | static const charset tags("%+"); | ||
| 85 | sref e,p=in; | ||
| 86 | while(p.nempty()) { | ||
| 87 | p=p.adv(e=p.left_first_of(tags)); | ||
| 88 | out<<e; | ||
| 89 | while(tags.test(p.front())) { | ||
| 90 | char c=*p; p=p.popf(); | ||
| 91 | if(c=='+') out.put(' '); | ||
| 92 | else if(c=='%') { | ||
| 93 | unsigned char c1=p[0],c2=p[1]; p=p.adv(2); | ||
| 94 | out.put(hexasc(c1,c2)); | ||
| 95 | } | ||
| 96 | else out.put(c); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | void Unpack(spile& list,const sref& in) | ||
| 102 | { | ||
| 103 | sref e,p=in; | ||
| 104 | while(p.nempty()) { | ||
| 105 | p=p.adv(e=p.left_first('&')).popf(); | ||
| 106 | if(e.nempty()) { | ||
| 107 | list.push_back(mstring()); | ||
| 108 | swrite sw(list.back()); | ||
| 109 | Unpack(sw,e); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | void Unpack(sspile& list,const sref& in) | ||
| 115 | { | ||
| 116 | sref e1,e2,p=in; | ||
| 117 | while(p.nempty()) { | ||
| 118 | p=p.adv(e1=p.left_first('=')).popf(); | ||
| 119 | if(e1.nempty()) { | ||
| 120 | p=p.adv(e2=p.left_first('&')).popf(); | ||
| 121 | list.push_back(sstring()); | ||
| 122 | swrite sw1(list.back().first); | ||
| 123 | Unpack(sw1,e1); | ||
| 124 | swrite sw2(list.back().second); | ||
| 125 | Unpack(sw2,e2); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | /////////////////////////////////////////////////////////////// | ||
| 131 | |||
| 132 | void CRLF2LF(mstream& out,const sref& in) | ||
| 133 | { | ||
| 134 | sref first,rest=in; | ||
| 135 | while(Splitln(first,rest)) out<<first<<"\n"; | ||
| 136 | } | ||
| 137 | |||
| 138 | void LF2CRLF(mstream& out,const sref& in) | ||
| 139 | { | ||
| 140 | sref first,rest=in; | ||
| 141 | while(Splitln(first,rest)) out<<first<<CRLF; | ||
| 142 | } | ||
| 143 | |||
diff --git a/src/mime/pack.h b/src/mime/pack.h new file mode 100644 index 0000000..e750aac --- /dev/null +++ b/src/mime/pack.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef PACKH | ||
| 21 | #define PACKH | ||
| 22 | |||
| 23 | #include <mt/mset.h> | ||
| 24 | #include <mt/msmap.h> | ||
| 25 | |||
| 26 | // Really mimefunctions, but needed here | ||
| 27 | |||
| 28 | mstream& cashex(mstream& out,unsigned char c); | ||
| 29 | char hexasc(unsigned char c1,unsigned char c2); | ||
| 30 | |||
| 31 | // Packing means application/x-www-form-urlencoded | ||
| 32 | |||
| 33 | void Unpack(mstream& out,const sref& in); | ||
| 34 | void Unpack(spile& list,const sref& in); | ||
| 35 | void Unpack(sspile& list,const sref& in); | ||
| 36 | |||
| 37 | void Pack(mstream& out,const sref& in); | ||
| 38 | void Pack(mstream& out,const rpile& list); | ||
| 39 | void Pack(mstream& out,const rrpile& list); | ||
| 40 | |||
| 41 | // CR LF and CRLF business | ||
| 42 | |||
| 43 | const mstring CRLF="\r\n"; | ||
| 44 | |||
| 45 | void CRLF2LF(mstream& out,const sref& in); | ||
| 46 | void LF2CRLF(mstream& out,const sref& in); | ||
| 47 | |||
| 48 | #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 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/enc.h> | ||
| 21 | #include <mime/pack.h> | ||
| 22 | #include <algorithm> | ||
| 23 | |||
| 24 | const charset special("=\"#$\\^`{|}~"); | ||
| 25 | //const charset special("=!\"#$@[\\]^`{|}~"); | ||
| 26 | const charset headspecial("_?"); | ||
| 27 | const charset printable=cset_printable&~special; | ||
| 28 | const charset printhead=printable&~headspecial; | ||
| 29 | const mstring beg_tag("=?"),end_tag("?="); | ||
| 30 | const mstring enc_qp_tag("Q"),enc_64_tag("B"); | ||
| 31 | const int WRAPAT=76; | ||
| 32 | const int HEADWRAP=WRAPAT-7; | ||
| 33 | |||
| 34 | void decodeQP(mstream& out,const sref& in) | ||
| 35 | { | ||
| 36 | const char* p=in.begin(); | ||
| 37 | while(p<in.end()) { | ||
| 38 | unsigned char c=*p++; | ||
| 39 | if(c=='=') { | ||
| 40 | if(cset_ws.test(*p)) p=in(p).past_nl().data(); | ||
| 41 | else { | ||
| 42 | unsigned char c1=*p++,c2=*p++; | ||
| 43 | out.put(hexasc(c1,c2)); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | else out.put(c); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | void encodeQP(mstream& out,const sref& in) | ||
| 51 | { | ||
| 52 | sref first,rest=in; | ||
| 53 | while(Splitln(first,rest)) { | ||
| 54 | int n=0; | ||
| 55 | const char* p=first.begin(); | ||
| 56 | while(p<first.end()) { | ||
| 57 | unsigned char c=*p++; | ||
| 58 | if(printable.test(c)) { | ||
| 59 | if(first(p).empty()&&cset_spaces.test(c)) { cashex(out.put('='),c); n+=3; } | ||
| 60 | else { out.put(c); n++; } | ||
| 61 | } | ||
| 62 | else { cashex(out.put('='),c); n+=3; } | ||
| 63 | if(first(p).nempty()&&n>=WRAPAT) { out.put('=')<<CRLF; n=0; } | ||
| 64 | } | ||
| 65 | out<<CRLF; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | static void decodeHQ(mstream& out,const sref& in) | ||
| 70 | { | ||
| 71 | const char* p=in.begin(); | ||
| 72 | while(p<in.end()) { | ||
| 73 | unsigned char c=*p++; | ||
| 74 | if(c=='=') { | ||
| 75 | unsigned char c1=*p++,c2=*p++; | ||
| 76 | out.put(hexasc(c1,c2)); | ||
| 77 | } | ||
| 78 | else if(c=='_') out.put(' '); | ||
| 79 | else out.put(c); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | static int encodeHQ(mstream& out,const sref& in) | ||
| 84 | { | ||
| 85 | int enc=0; | ||
| 86 | const char* p=in.begin(); | ||
| 87 | while(p<in.end()) { | ||
| 88 | unsigned char c=*p++; | ||
| 89 | if(!printable.test(c)) enc=1; | ||
| 90 | if(printhead.test(c)) { if(c==32) out.put('_'); else out.put(c); } | ||
| 91 | else cashex(out.put('='),c); | ||
| 92 | } | ||
| 93 | return enc; | ||
| 94 | } | ||
| 95 | |||
| 96 | void decodeHeader(mstream& out,mstring& mime,const sref& in) | ||
| 97 | { | ||
| 98 | sref e,p=in; | ||
| 99 | while(p.nempty()) { | ||
| 100 | p=p.adv(e=p.left_first(beg_tag)); | ||
| 101 | out<<e; | ||
| 102 | if(p.nempty()) { | ||
| 103 | p=p.adv(beg_tag.size()); | ||
| 104 | mime=p.left_first('?'); | ||
| 105 | p=p.adv(mime.size()); | ||
| 106 | if(p.empty()) { out<<beg_tag<<mime; p.clear(); } | ||
| 107 | else { | ||
| 108 | p=p.popf(); | ||
| 109 | sref enc=p.left_first('?'); | ||
| 110 | p=p.adv(enc); | ||
| 111 | if(p.empty()) { out<<beg_tag<<mime<<"?"<<enc; p.clear(); } | ||
| 112 | else { | ||
| 113 | p=p.adv(e=p.popf().left_first(end_tag)); | ||
| 114 | if(p.empty()) { out<<beg_tag<<mime<<"?"<<enc<<"?"<<e; p.clear(); } | ||
| 115 | else { | ||
| 116 | p=p.adv(end_tag.size()); | ||
| 117 | if(eqn(enc,enc_qp_tag)) decodeHQ(out,e); | ||
| 118 | else if(eqn(enc,enc_64_tag)) decode64(out,e); | ||
| 119 | else out<<"BAD: ["<<mime<<"]["<<enc<<"]["<<e<<"]"; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | void encodeHeader(mstream& out,const sref& mime,const sref& in) | ||
| 128 | { | ||
| 129 | mstring tmp; | ||
| 130 | swrite sw(tmp); | ||
| 131 | if(encodeHQ(sw,in)) { | ||
| 132 | int wrapat=HEADWRAP-mime.size(); | ||
| 133 | sref e,p=tmp; | ||
| 134 | p=p.adv(e=p.left(std::min(wrapat,p.size()))); | ||
| 135 | out<<beg_tag<<mime<<"?Q?"<<e<<end_tag; | ||
| 136 | while(p.nempty()) { | ||
| 137 | p=p.adv(e=p.left(std::min(wrapat,p.size()))); | ||
| 138 | out<<"\r\n\t"<<beg_tag<<mime<<"?Q?"<<e<<end_tag; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | else { | ||
| 142 | sref e,p=in; | ||
| 143 | p=p.adv(e=p.left(std::min(WRAPAT,p.size()))); | ||
| 144 | out<<e; | ||
| 145 | while(p.nempty()) { | ||
| 146 | p=p.adv(e=p.left(std::min(WRAPAT,p.size()))); | ||
| 147 | out<<"\r\n\t"<<e; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
diff --git a/src/mime/test.cc b/src/mime/test.cc new file mode 100644 index 0000000..6392904 --- /dev/null +++ b/src/mime/test.cc | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /************************************************************************* | ||
| 2 | * | ||
| 3 | * HTCd - Copyright (C) 1998-2006 Henrik Rydberg | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <mime/mailbox.h> | ||
| 21 | #include <mime/mime.h> | ||
| 22 | #include <mime/enc.h> | ||
| 23 | #include <sys/stat.h> | ||
| 24 | |||
| 25 | static fp_stream mout(stdout),merr(stderr); | ||
| 26 | |||
| 27 | static void Show(mstream& out,const Message& msg) | ||
| 28 | { | ||
| 29 | if(msg.cont_type.empty()|| | ||
| 30 | eqn(msg.cont_type,mime_textplain)|| | ||
| 31 | eqn(msg.cont_type,mime_texthtml)) { | ||
| 32 | if(eqn(msg.cont_trans_enc,trans_quote)) { | ||
| 33 | //decodeQP(out,msg.body); | ||
| 34 | mswrite tmp; | ||
| 35 | decodeQP(tmp,msg.body); | ||
| 36 | encodeQP(out,tmp.str()); | ||
| 37 | } | ||
| 38 | else { | ||
| 39 | //out<<msg.body<<"\n"; | ||
| 40 | encodeQP(out,msg.body); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | else out<<"(not shown)\n"; | ||
| 44 | } | ||
| 45 | |||
| 46 | main(int argc,char* argv[]) | ||
| 47 | { | ||
| 48 | if(argc<2) { | ||
| 49 | merr<<"Usage: "<<argv[0]<<" <source> [index]\n"; | ||
| 50 | return 1; | ||
| 51 | } | ||
| 52 | Mailbox box; | ||
| 53 | GetMessages(box,argv[1]); | ||
| 54 | merr<<"Found "<<box.size()<<" messages\n"; | ||
| 55 | if(argc>2) { | ||
| 56 | Message msg(box[atoi(argv[2])]); | ||
| 57 | //msg.Pick(mime_textplain); | ||
| 58 | |||
| 59 | mswrite tmp; | ||
| 60 | encodeHeader(tmp,mime_default,msg.subject); | ||
| 61 | msg.subject=tmp.str(); | ||
| 62 | |||
| 63 | msg.putHead(mout); | ||
| 64 | mout<<"-----------------------------------------\n"; | ||
| 65 | rpile part; | ||
| 66 | if(msg.Multipart(part)) { | ||
| 67 | for(int i=0;i<part.size();i++) { | ||
| 68 | Message pm(part[i]); | ||
| 69 | pm.putHead(mout); | ||
| 70 | mout<<"-------------------------------\n"; | ||
| 71 | Show(mout,pm); | ||
| 72 | mout<<"-------------------------------\n"; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | else { | ||
| 76 | Show(mout,msg); | ||
| 77 | } | ||
| 78 | |||
| 79 | mout<<"**********\n"; | ||
| 80 | mout<<msg.head; | ||
| 81 | mout<<"**********\n"; | ||
| 82 | mout<<msg.body; | ||
| 83 | mout<<"**********\n"; | ||
| 84 | |||
| 85 | } | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | main(int argc,char* argv[]) | ||
| 92 | { | ||
| 93 | if(argc<2) { | ||
| 94 | merr<<"Usage: "<<argv[0]<<" <source>\n"; | ||
| 95 | return 1; | ||
| 96 | } | ||
| 97 | mstring buffer; buffer.load(argv[1]); | ||
| 98 | merr<<buffer.size()<<"\n"; | ||
| 99 | mswrite enc; | ||
| 100 | encode64(enc,buffer); | ||
| 101 | merr<<enc.str().size()<<"\n"; | ||
| 102 | mswrite nbuf; | ||
| 103 | decode64(nbuf,enc.str()); | ||
| 104 | merr<<nbuf.str().size()<<"\n"; | ||
| 105 | if(nbuf.str()==buffer) merr<<"Match.\n"; | ||
| 106 | mout<<enc.str(); | ||
| 107 | } | ||
| 108 | */ | ||
