Fossil SCM

fossil-scm / tools / decode-email.c
Source Blame History 163 lines
17b4d3e… drh 1 /*
17b4d3e… drh 2 ** This program reads a raw email file and attempts to decode it into
17b4d3e… drh 3 ** a more human-readable format. The following decodings are done:
17b4d3e… drh 4 **
17b4d3e… drh 5 ** (1) Header values are prefixed by "| " at the left margin.
17b4d3e… drh 6 **
17b4d3e… drh 7 ** (2) Content-Transfer-Encoding is recognized and the content is
17b4d3e… drh 8 ** decoded for display.
17b4d3e… drh 9 */
17b4d3e… drh 10 #define _GNU_SOURCE
17b4d3e… drh 11 #include <stdio.h>
17b4d3e… drh 12 #include <string.h>
17b4d3e… drh 13 #include <ctype.h>
17b4d3e… drh 14
17b4d3e… drh 15 #define BINARY 0
17b4d3e… drh 16 #define BASE64 1
17b4d3e… drh 17 #define QUOTED 2
17b4d3e… drh 18
17b4d3e… drh 19 static int decode_hex(char c){
17b4d3e… drh 20 if( c>='0' && c<='9' ) return c - '0';
17b4d3e… drh 21 if( c>='A' && c<='F' ) return c - 'A' + 10;
17b4d3e… drh 22 if( c>='a' && c<='f' ) return c - 'a' + 10;
17b4d3e… drh 23 return -1;
17b4d3e… drh 24 }
17b4d3e… drh 25
17b4d3e… drh 26 static void convert_file(const char *zFilename, FILE *in){
17b4d3e… drh 27 int inHdr = 1;
17b4d3e… drh 28 int n;
17b4d3e… drh 29 int nBoundary;
17b4d3e… drh 30 int decodeType = 0;
17b4d3e… drh 31 int textMimetype = 1;
17b4d3e… drh 32 char *zB;
17b4d3e… drh 33 char zBoundary[200];
17b4d3e… drh 34 char zLine[5000];
17b4d3e… drh 35 char zOut[5000];
17b4d3e… drh 36 while( fgets(zLine, sizeof(zLine), in) ){
17b4d3e… drh 37 if( !inHdr
17b4d3e… drh 38 && zLine[0]=='-'
17b4d3e… drh 39 && zLine[1]=='-'
17b4d3e… drh 40 && strncmp(zLine+2,zBoundary,nBoundary)==0
17b4d3e… drh 41 ){
17b4d3e… drh 42 printf("|----------------- end of body section ---------|\n");
17b4d3e… drh 43 inHdr = 1;
17b4d3e… drh 44 }
17b4d3e… drh 45 if( !inHdr ){
17b4d3e… drh 46 if( textMimetype && decodeType==BASE64 ){
17b4d3e… drh 47 int ii, jj, c, x, y;
17b4d3e… drh 48 int bits = 0;
17b4d3e… drh 49 for(ii=jj=0; (c = zLine[ii])!=0; ii++){
17b4d3e… drh 50 if( c>='A' && c<='Z' ){
17b4d3e… drh 51 x = c - 'A';
17b4d3e… drh 52 }else if( c>='a' && c<='z' ){
17b4d3e… drh 53 x = c - 'a' + 26;
17b4d3e… drh 54 }else if( c>='0' && c<='9' ){
17b4d3e… drh 55 x = c - '0' + 52;
17b4d3e… drh 56 }else if( c=='+' ){
17b4d3e… drh 57 x = 62;
17b4d3e… drh 58 }else if( c=='/' ){
17b4d3e… drh 59 x = 63;
17b4d3e… drh 60 }else if( c=='=' ){
17b4d3e… drh 61 x = 0;
17b4d3e… drh 62 }else{
17b4d3e… drh 63 continue;
17b4d3e… drh 64 }
17b4d3e… drh 65 if( bits==0 ){
17b4d3e… drh 66 y = x;
17b4d3e… drh 67 bits = 6;
17b4d3e… drh 68 }else if( bits==6 ){
17b4d3e… drh 69 zOut[jj++] = ((y<<2) & 0xfc) | ((x>>4) & 0x03);
17b4d3e… drh 70 y = x & 0xf;
17b4d3e… drh 71 bits = 4;
17b4d3e… drh 72 }else if( bits==4 ){
17b4d3e… drh 73 zOut[jj++] = ((y<<4) & 0xf0) | ((x>>2) & 0x0f);
17b4d3e… drh 74 y = x & 0x3;
17b4d3e… drh 75 bits = 2;
17b4d3e… drh 76 }else if( bits==2 ){
17b4d3e… drh 77 zOut[jj++] = ((y<<6) & 0xc0) | (x & 0x3f);
17b4d3e… drh 78 bits = 0;
17b4d3e… drh 79 }
17b4d3e… drh 80 }
17b4d3e… drh 81 zOut[jj] = 0;
17b4d3e… drh 82 printf("%s", zOut);
17b4d3e… drh 83 }else if( textMimetype && decodeType==QUOTED ){
17b4d3e… drh 84 int ii, jj, c;
17b4d3e… drh 85 for(ii=jj=0; (c = zLine[ii])!=0; ii++){
17b4d3e… drh 86 if( c=='=' ){
17b4d3e… drh 87 int x1 = decode_hex(zLine[ii+1]);
17b4d3e… drh 88 int x2 = decode_hex(zLine[ii+2]);
17b4d3e… drh 89 if( x1>=0 && x2>=0 ){
17b4d3e… drh 90 zOut[jj++] = (x1<<4) | x2;
17b4d3e… drh 91 ii += 2;
17b4d3e… drh 92 }else if( zLine[ii+1]=='\r' && zLine[ii+2]=='\n' ){
17b4d3e… drh 93 ii += 2;
17b4d3e… drh 94 }
17b4d3e… drh 95 }else{
17b4d3e… drh 96 zOut[jj++] = c;
17b4d3e… drh 97 }
17b4d3e… drh 98 }
17b4d3e… drh 99 zOut[jj] = 0;
17b4d3e… drh 100 printf("%s", zOut);
17b4d3e… drh 101 }else{
17b4d3e… drh 102 printf("%s", zLine);
17b4d3e… drh 103 }
17b4d3e… drh 104 continue;
17b4d3e… drh 105 }
17b4d3e… drh 106 n = (int)strlen(zLine);
17b4d3e… drh 107 while( n>0 && isspace(zLine[n-1]) ){ n--; }
17b4d3e… drh 108 zLine[n] = 0;
17b4d3e… drh 109 if( n==0 ){
17b4d3e… drh 110 inHdr = 0;
17b4d3e… drh 111 printf("|----------------- end of header ---------------|\n");
17b4d3e… drh 112 continue;
17b4d3e… drh 113 }
17b4d3e… drh 114 printf("| %s\n", zLine);
17b4d3e… drh 115 if( strncasecmp(zLine,"Content-Type:", 13)==0 ){
17b4d3e… drh 116 textMimetype = strstr(zLine, "text/")!=0;
17b4d3e… drh 117 printf("|** %s content type **|\n",
17b4d3e… drh 118 textMimetype ? "Text" : "Non-text");
17b4d3e… drh 119 }
17b4d3e… drh 120 if( strncasecmp(zLine,"Content-Transfer-Encoding:", 26)==0 ){
17b4d3e… drh 121 if( strcasestr(zLine, "base64") ){
17b4d3e… drh 122 decodeType = BASE64;
17b4d3e… drh 123 }else if( strcasestr(zLine, "quoted-printable") ){
17b4d3e… drh 124 decodeType = QUOTED;
17b4d3e… drh 125 }else{
17b4d3e… drh 126 decodeType = BINARY;
17b4d3e… drh 127 }
17b4d3e… drh 128 printf("|** Content encoding %s **|\n",
17b4d3e… drh 129 decodeType==BASE64 ? "BASE64" :
17b4d3e… drh 130 decodeType==QUOTED ? "QUOTED" : "BINARY");
17b4d3e… drh 131 }
17b4d3e… drh 132 zB = strstr(zLine, "boundary=\"");
17b4d3e… drh 133 if( zB ){
17b4d3e… drh 134 int kk;
17b4d3e… drh 135 zB += 10;
17b4d3e… drh 136 for(kk=0; zB[kk] && zB[kk]!='"' && kk<sizeof(zBoundary)-1; kk++){
17b4d3e… drh 137 zBoundary[kk] = zB[kk];
17b4d3e… drh 138 }
17b4d3e… drh 139 zBoundary[kk] = 0;
17b4d3e… drh 140 nBoundary = kk;
17b4d3e… drh 141 printf("|** boundary [%s] **|\n", zBoundary);
17b4d3e… drh 142 }
17b4d3e… drh 143 }
17b4d3e… drh 144 }
17b4d3e… drh 145
17b4d3e… drh 146 int main(int argc, char **argv){
17b4d3e… drh 147 if( argc==1 ){
17b4d3e… drh 148 convert_file("<stdin>", stdin);
17b4d3e… drh 149 return 0;
17b4d3e… drh 150 }else{
17b4d3e… drh 151 int i;
17b4d3e… drh 152 for(i=1; i<argc; i++){
17b4d3e… drh 153 FILE *in = fopen(argv[i], "rb");
17b4d3e… drh 154 if( in==0 ){
17b4d3e… drh 155 fprintf(stderr, "cannot open \"%s\"", argv[i]);
17b4d3e… drh 156 }else{
17b4d3e… drh 157 convert_file(argv[i], in);
17b4d3e… drh 158 fclose(in);
17b4d3e… drh 159 }
17b4d3e… drh 160 }
17b4d3e… drh 161 }
17b4d3e… drh 162 return 0;
17b4d3e… drh 163 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button