summaryrefslogtreecommitdiff
path: root/tools/decode-email.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/decode-email.c')
-rw-r--r--tools/decode-email.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/tools/decode-email.c b/tools/decode-email.c
new file mode 100644
index 0000000..8945394
--- /dev/null
+++ b/tools/decode-email.c
@@ -0,0 +1,163 @@
+/*
+** This program reads a raw email file and attempts to decode it into
+** a more human-readable format. The following decodings are done:
+**
+** (1) Header values are prefixed by "| " at the left margin.
+**
+** (2) Content-Transfer-Encoding is recognized and the content is
+** decoded for display.
+*/
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define BINARY 0
+#define BASE64 1
+#define QUOTED 2
+
+static int decode_hex(char c){
+ if( c>='0' && c<='9' ) return c - '0';
+ if( c>='A' && c<='F' ) return c - 'A' + 10;
+ if( c>='a' && c<='f' ) return c - 'a' + 10;
+ return -1;
+}
+
+static void convert_file(const char *zFilename, FILE *in){
+ int inHdr = 1;
+ int n;
+ int nBoundary;
+ int decodeType = 0;
+ int textMimetype = 1;
+ char *zB;
+ char zBoundary[200];
+ char zLine[5000];
+ char zOut[5000];
+ while( fgets(zLine, sizeof(zLine), in) ){
+ if( !inHdr
+ && zLine[0]=='-'
+ && zLine[1]=='-'
+ && strncmp(zLine+2,zBoundary,nBoundary)==0
+ ){
+ printf("|----------------- end of body section ---------|\n");
+ inHdr = 1;
+ }
+ if( !inHdr ){
+ if( textMimetype && decodeType==BASE64 ){
+ int ii, jj, c, x, y;
+ int bits = 0;
+ for(ii=jj=0; (c = zLine[ii])!=0; ii++){
+ if( c>='A' && c<='Z' ){
+ x = c - 'A';
+ }else if( c>='a' && c<='z' ){
+ x = c - 'a' + 26;
+ }else if( c>='0' && c<='9' ){
+ x = c - '0' + 52;
+ }else if( c=='+' ){
+ x = 62;
+ }else if( c=='/' ){
+ x = 63;
+ }else if( c=='=' ){
+ x = 0;
+ }else{
+ continue;
+ }
+ if( bits==0 ){
+ y = x;
+ bits = 6;
+ }else if( bits==6 ){
+ zOut[jj++] = ((y<<2) & 0xfc) | ((x>>4) & 0x03);
+ y = x & 0xf;
+ bits = 4;
+ }else if( bits==4 ){
+ zOut[jj++] = ((y<<4) & 0xf0) | ((x>>2) & 0x0f);
+ y = x & 0x3;
+ bits = 2;
+ }else if( bits==2 ){
+ zOut[jj++] = ((y<<6) & 0xc0) | (x & 0x3f);
+ bits = 0;
+ }
+ }
+ zOut[jj] = 0;
+ printf("%s", zOut);
+ }else if( textMimetype && decodeType==QUOTED ){
+ int ii, jj, c;
+ for(ii=jj=0; (c = zLine[ii])!=0; ii++){
+ if( c=='=' ){
+ int x1 = decode_hex(zLine[ii+1]);
+ int x2 = decode_hex(zLine[ii+2]);
+ if( x1>=0 && x2>=0 ){
+ zOut[jj++] = (x1<<4) | x2;
+ ii += 2;
+ }else if( zLine[ii+1]=='\r' && zLine[ii+2]=='\n' ){
+ ii += 2;
+ }
+ }else{
+ zOut[jj++] = c;
+ }
+ }
+ zOut[jj] = 0;
+ printf("%s", zOut);
+ }else{
+ printf("%s", zLine);
+ }
+ continue;
+ }
+ n = (int)strlen(zLine);
+ while( n>0 && isspace(zLine[n-1]) ){ n--; }
+ zLine[n] = 0;
+ if( n==0 ){
+ inHdr = 0;
+ printf("|----------------- end of header ---------------|\n");
+ continue;
+ }
+ printf("| %s\n", zLine);
+ if( strncasecmp(zLine,"Content-Type:", 13)==0 ){
+ textMimetype = strstr(zLine, "text/")!=0;
+ printf("|** %s content type **|\n",
+ textMimetype ? "Text" : "Non-text");
+ }
+ if( strncasecmp(zLine,"Content-Transfer-Encoding:", 26)==0 ){
+ if( strcasestr(zLine, "base64") ){
+ decodeType = BASE64;
+ }else if( strcasestr(zLine, "quoted-printable") ){
+ decodeType = QUOTED;
+ }else{
+ decodeType = BINARY;
+ }
+ printf("|** Content encoding %s **|\n",
+ decodeType==BASE64 ? "BASE64" :
+ decodeType==QUOTED ? "QUOTED" : "BINARY");
+ }
+ zB = strstr(zLine, "boundary=\"");
+ if( zB ){
+ int kk;
+ zB += 10;
+ for(kk=0; zB[kk] && zB[kk]!='"' && kk<sizeof(zBoundary)-1; kk++){
+ zBoundary[kk] = zB[kk];
+ }
+ zBoundary[kk] = 0;
+ nBoundary = kk;
+ printf("|** boundary [%s] **|\n", zBoundary);
+ }
+ }
+}
+
+int main(int argc, char **argv){
+ if( argc==1 ){
+ convert_file("<stdin>", stdin);
+ return 0;
+ }else{
+ int i;
+ for(i=1; i<argc; i++){
+ FILE *in = fopen(argv[i], "rb");
+ if( in==0 ){
+ fprintf(stderr, "cannot open \"%s\"", argv[i]);
+ }else{
+ convert_file(argv[i], in);
+ fclose(in);
+ }
+ }
+ }
+ return 0;
+}