dmc

dynamic mail client
git clone git://git.suckless.org/dmc
Log | Files | Refs | README | LICENSE

pack.c (4653B)


      1 /* dmc - dynamic mail client
      2  * See LICENSE file for copyright and license details.
      3  */
      4 
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 
     10 #define SZ 1024
     11 static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     12 static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
     13 
     14 static void b64_encode(unsigned char in[3], unsigned char out[4], int len) {
     15 	out[0] = cb64[ in[0] >> 2 ];
     16 	out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
     17 	out[2] = (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
     18 	out[3] = (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
     19 }
     20 
     21 static int b64_decode(unsigned char in[4], unsigned char out[3]) {
     22 	unsigned char len = 3, i, v[4];
     23 	for(i=0;i<4;i++) {
     24 		if (in[i]<43||in[i]>122)
     25 			return -1;
     26 		v[i] = cd64[in[i]-43];
     27 		if (v[i]!='$') v[i]-=62;
     28 		else { len = i-1; break; }
     29 	}
     30 	out[0] = v[0] << 2 | v[1] >> 4;
     31 	out[1] = v[1] << 4 | v[2] >> 2;
     32 	out[2] = ((v[2] << 6) & 0xc0) | v[3];
     33 	return len;
     34 }
     35 
     36 static void mime_pack(char **files, int nfiles) {
     37 	FILE *fd = NULL;
     38 	char b[SZ], cmd[SZ], *ptr = NULL, *ptr2 = NULL;
     39 	unsigned char bd[SZ];
     40 	int header = 1, len, in, out, i;
     41 
     42 	memset (b, '\0', SZ);
     43 	while(fgets (b, SZ-1, stdin)) {
     44 		if (header && b[0] == '\n') {
     45 			printf ("Content-Type: multipart/mixed; boundary=\"dmc-multipart\"\n\n"
     46 				"--dmc-multipart\n"
     47 				"Content-Type: text/plain\n");
     48 			header = 0;
     49 		}
     50 		fputs (b, stdout);
     51 	}
     52 	for(i = 0; i < nfiles; i++) {
     53 		snprintf (cmd, SZ-1, "file -iL \"%s\"", files[i]);
     54 		if (!(fd=popen (cmd, "r")))
     55 			continue;
     56 		fgets (b, SZ-1, fd);
     57 		pclose (fd);
     58 		if (!(ptr = strchr(b, ' ')))
     59 			continue;
     60 		if (!(fd=fopen(files[i], "r")))
     61 			continue;
     62 		if ((ptr2 = strrchr(files[i], '/')))
     63 			ptr2++;
     64 		else ptr2 = files[i];
     65 		puts ("--dmc-multipart");
     66 		printf ("Content-Type: %s", ptr+1);
     67 		printf ("Content-Disposition: attachment; filename=\"%s\"\n", ptr2);
     68 		if (strstr (ptr, "text")) {
     69 			printf("Content-Transfer-Encoding: quoted-printable\n\n");
     70 			while (fgets(b, SZ-1, fd))
     71 				printf("%s", b);
     72 		} else {
     73 			puts ("Content-Transfer-Encoding: base64\n");
     74 			while ((len=fread (b, 1, 57, fd))) {
     75 				memset (bd, '\0', SZ);
     76 				for (in=out=0;in<len;in+=3,out+=4)
     77 					b64_encode ((unsigned char*)b+in,bd+out,len-in>3?3:len-in);
     78 				puts ((char *)bd);
     79 			}
     80 		}
     81 		fclose (fd);
     82 	}
     83 	puts ("--dmc-multipart--");
     84 }
     85 
     86 static void mime_unpack (int xtr) {
     87 	FILE *fd = NULL;
     88 	char b[SZ], boundary[SZ], encoding[SZ], filename[SZ], *ptr, *ptr2;
     89 	unsigned char bd[SZ];
     90 	int entity = 0, dump = 0, empty = 0, len, in, out, i, n = 0;
     91 
     92 	boundary[0] = encoding[0] = filename[0] = '\0';
     93 	memset (b, '\0', SZ);
     94 	while (fgets(b, SZ-1, stdin)) {
     95 		if (!memcmp(b, "--", 2)) {
     96 			if (boundary[0] && strstr(b, boundary) &&
     97 					!memcmp(b+strlen(b)-3, "--", 2)) {
     98 				entity = dump = empty = 0;
     99 			} else {
    100 				strncpy(boundary, b+2, SZ-1);
    101 				if ((len = strlen(boundary)) > 0)
    102 					boundary[len-1] = '\0';
    103 				if (fgets(b, SZ-1, stdin) && strstr(b, "Content-Type:")) {
    104 					entity = 1;
    105 					dump = empty = 0;
    106 				}
    107 			}
    108 		}
    109 		if (entity) {
    110 			if ((ptr = strstr(b, "Content-Transfer-Encoding:"))) {
    111 				strncpy(encoding, ptr+26, SZ-1);
    112 			} else if ((ptr = strstr(b, "filename=")) && 
    113 					((ptr2 = strchr(ptr, '"')) || (ptr2 = strchr(ptr, '=')))) {
    114 				strncpy(filename, ptr2+1, SZ-1);
    115 				if ((ptr = strchr(filename, '"')) ||
    116 					(ptr = strchr(filename, ' ')) ||
    117 					(ptr = strchr(filename, '\n')))
    118 					ptr[0] = '\0';
    119 				puts (filename);
    120 			} else if (strstr(b, "boundary=")) {
    121 				empty = 1;
    122 			} else if (b[0] == '\n') {
    123 				if (!empty && !filename[0])
    124 					snprintf(filename, SZ-1, "mimepart-%i", n++);
    125 				if (xtr && !dump && filename[0] && (fd = fopen(filename, "w"))) {
    126 					dump = 1;
    127 					continue;
    128 				} else if (dump && strstr(encoding, "base64"))
    129 					dump = 0;
    130 			} 
    131 		} else boundary[0] = '\0';
    132 		if (dump) {
    133 			if (strstr(encoding, "base64")) {
    134 				memset(bd,'\0',SZ);
    135 				if ((len = strlen(b)) > 0)
    136 					b[len-1] = '\0';
    137 				for(in=out=0;in<len-1;in+=4)
    138 					out+=b64_decode((unsigned char*)b+in,bd+out);
    139 				for(i=0;i<out;i++)
    140 					fputc(bd[i], fd);
    141 			} else fputs(b, fd); 
    142 		} else if (fd) {
    143 			fclose(fd);
    144 			fd = NULL;
    145 			encoding[0] = filename[0] = '\0';
    146 		}
    147 	}
    148 }
    149 
    150 int main(int argc, char **argv) {
    151 	if (argc < 2) {
    152 		mime_pack (argv+1, argc-1);
    153 	} else if (!strcmp(argv[1], "-h")) {
    154 		fprintf (stderr, "Usage: %s [-hlu | attachment1 attachment2...] < mail\n", argv[0]);
    155 		return 1;
    156 	} else if (!strcmp(argv[1], "-l"))
    157 		mime_unpack (0);
    158 	else if (!strcmp(argv[1], "-u"))
    159 		mime_unpack (1);
    160 	else mime_pack(argv+1, argc-1);
    161 	return 0;
    162 }