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 }