Fossil SCM

Fully function email message decoder now in place.

drh 2018-07-12 23:03 trunk
Commit d0ae0898ded03e032ed1df2447ce4b37c6bfa99c3b3b0c7f042aec1aba61d31e
2 files changed +68 -35 +20 -1
+68 -35
--- src/encode.c
+++ src/encode.c
@@ -492,10 +492,50 @@
492492
fossil_print("%s\n", z);
493493
free(z);
494494
}
495495
}
496496
497
+
498
+/* Decode base64 text. Write the output into zData. The caller
499
+** must ensure that zData is large enough. It is ok for z64 and
500
+** zData to be the same buffer. In other words, it is ok to decode
501
+** in-place. A zero terminator is always placed at the end of zData.
502
+*/
503
+void decodeBase64(const char *z64, int *pnByte, char *zData){
504
+ const unsigned char *zIn = (const unsigned char*)z64;
505
+ int i, j, k;
506
+ int x[4];
507
+ static int isInit = 0;
508
+ static signed char trans[256];
509
+
510
+ if( !isInit ){
511
+ for(i=0; i<256; i++){ trans[i] = -1; }
512
+ for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
513
+ isInit = 1;
514
+ }
515
+ for(j=k=0; zIn[0]; zIn++){
516
+ int v = trans[zIn[0]];
517
+ if( v>=0 ){
518
+ x[k++] = v;
519
+ if( k==4 ){
520
+ zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
521
+ zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
522
+ zData[j++] = ((x[2]<<6) & 0xc0) | (x[3] & 0x3f);
523
+ k = 0;
524
+ }
525
+ }
526
+ }
527
+ if( k>=2 ){
528
+ zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
529
+ if( k==3 ){
530
+ zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
531
+ }
532
+ }
533
+ zData[j] = 0;
534
+ *pnByte = j;
535
+}
536
+
497537
498538
/*
499539
** This function treats its input as a base-64 string and returns the
500540
** decoded value of that string. Characters of input that are not
501541
** valid base-64 characters (such as spaces and newlines) are ignored.
@@ -504,46 +544,14 @@
504544
**
505545
** The number of bytes decoded is returned in *pnByte
506546
*/
507547
char *decode64(const char *z64, int *pnByte){
508548
char *zData;
509
- int n64;
510
- int i, j;
511
- int a, b, c, d;
512
- static int isInit = 0;
513
- static int trans[128];
514
-
515
- if( !isInit ){
516
- for(i=0; i<128; i++){ trans[i] = 0; }
517
- for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
518
- isInit = 1;
519
- }
520
- n64 = strlen(z64);
549
+ int n64 = (int)strlen(z64);
521550
while( n64>0 && z64[n64-1]=='=' ) n64--;
522551
zData = fossil_malloc( (n64*3)/4 + 4 );
523
- for(i=j=0; i+3<n64; i+=4){
524
- a = trans[z64[i] & 0x7f];
525
- b = trans[z64[i+1] & 0x7f];
526
- c = trans[z64[i+2] & 0x7f];
527
- d = trans[z64[i+3] & 0x7f];
528
- zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
529
- zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
530
- zData[j++] = ((c<<6) & 0xc0) | (d & 0x3f);
531
- }
532
- if( i+2<n64 ){
533
- a = trans[z64[i] & 0x7f];
534
- b = trans[z64[i+1] & 0x7f];
535
- c = trans[z64[i+2] & 0x7f];
536
- zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
537
- zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
538
- }else if( i+1<n64 ){
539
- a = trans[z64[i] & 0x7f];
540
- b = trans[z64[i+1] & 0x7f];
541
- zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
542
- }
543
- zData[j] = 0;
544
- *pnByte = j;
552
+ decodeBase64(z64, pnByte, zData);
545553
return zData;
546554
}
547555
548556
/*
549557
** COMMAND: test-decode64
@@ -554,11 +562,11 @@
554562
char *z;
555563
int i, n;
556564
for(i=2; i<g.argc; i++){
557565
z = decode64(g.argv[i], &n);
558566
fossil_print("%d: %s\n", n, z);
559
- free(z);
567
+ fossil_free(z);
560568
}
561569
}
562570
563571
/*
564572
** The base-16 encoding using the following characters:
@@ -654,10 +662,35 @@
654662
while( *z && n-- ){
655663
*z = zEncode[zDecode[(*z)&0x7f]&0x1f];
656664
z++;
657665
}
658666
}
667
+
668
+/*
669
+** Decode a string encoded using "quoted-printable".
670
+**
671
+** (1) "=" followed by two hex digits becomes a single
672
+** byte specified by the two digits
673
+**
674
+** The decoding is done in-place.
675
+*/
676
+void decodeQuotedPrintable(char *z, int *pnByte){
677
+ int i, j, c;
678
+ for(i=j=0; (c = z[i])!=0; i++){
679
+ if( c=='=' ){
680
+ if( z[i+1]!='\r' ){
681
+ decode16((unsigned char*)&z[i+1], (unsigned char*)&z[j], 2);
682
+ j++;
683
+ }
684
+ i += 2;
685
+ }else{
686
+ z[j++] = c;
687
+ }
688
+ }
689
+ if( pnByte ) *pnByte = j;
690
+ z[j] = 0;
691
+}
659692
660693
/* Randomness used for XOR-ing by the obscure() and unobscure() routines */
661694
static const unsigned char aObscurer[16] = {
662695
0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86,
663696
0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85
664697
--- src/encode.c
+++ src/encode.c
@@ -492,10 +492,50 @@
492 fossil_print("%s\n", z);
493 free(z);
494 }
495 }
496
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
498 /*
499 ** This function treats its input as a base-64 string and returns the
500 ** decoded value of that string. Characters of input that are not
501 ** valid base-64 characters (such as spaces and newlines) are ignored.
@@ -504,46 +544,14 @@
504 **
505 ** The number of bytes decoded is returned in *pnByte
506 */
507 char *decode64(const char *z64, int *pnByte){
508 char *zData;
509 int n64;
510 int i, j;
511 int a, b, c, d;
512 static int isInit = 0;
513 static int trans[128];
514
515 if( !isInit ){
516 for(i=0; i<128; i++){ trans[i] = 0; }
517 for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
518 isInit = 1;
519 }
520 n64 = strlen(z64);
521 while( n64>0 && z64[n64-1]=='=' ) n64--;
522 zData = fossil_malloc( (n64*3)/4 + 4 );
523 for(i=j=0; i+3<n64; i+=4){
524 a = trans[z64[i] & 0x7f];
525 b = trans[z64[i+1] & 0x7f];
526 c = trans[z64[i+2] & 0x7f];
527 d = trans[z64[i+3] & 0x7f];
528 zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
529 zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
530 zData[j++] = ((c<<6) & 0xc0) | (d & 0x3f);
531 }
532 if( i+2<n64 ){
533 a = trans[z64[i] & 0x7f];
534 b = trans[z64[i+1] & 0x7f];
535 c = trans[z64[i+2] & 0x7f];
536 zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
537 zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
538 }else if( i+1<n64 ){
539 a = trans[z64[i] & 0x7f];
540 b = trans[z64[i+1] & 0x7f];
541 zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
542 }
543 zData[j] = 0;
544 *pnByte = j;
545 return zData;
546 }
547
548 /*
549 ** COMMAND: test-decode64
@@ -554,11 +562,11 @@
554 char *z;
555 int i, n;
556 for(i=2; i<g.argc; i++){
557 z = decode64(g.argv[i], &n);
558 fossil_print("%d: %s\n", n, z);
559 free(z);
560 }
561 }
562
563 /*
564 ** The base-16 encoding using the following characters:
@@ -654,10 +662,35 @@
654 while( *z && n-- ){
655 *z = zEncode[zDecode[(*z)&0x7f]&0x1f];
656 z++;
657 }
658 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
660 /* Randomness used for XOR-ing by the obscure() and unobscure() routines */
661 static const unsigned char aObscurer[16] = {
662 0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86,
663 0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85
664
--- src/encode.c
+++ src/encode.c
@@ -492,10 +492,50 @@
492 fossil_print("%s\n", z);
493 free(z);
494 }
495 }
496
497
498 /* Decode base64 text. Write the output into zData. The caller
499 ** must ensure that zData is large enough. It is ok for z64 and
500 ** zData to be the same buffer. In other words, it is ok to decode
501 ** in-place. A zero terminator is always placed at the end of zData.
502 */
503 void decodeBase64(const char *z64, int *pnByte, char *zData){
504 const unsigned char *zIn = (const unsigned char*)z64;
505 int i, j, k;
506 int x[4];
507 static int isInit = 0;
508 static signed char trans[256];
509
510 if( !isInit ){
511 for(i=0; i<256; i++){ trans[i] = -1; }
512 for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
513 isInit = 1;
514 }
515 for(j=k=0; zIn[0]; zIn++){
516 int v = trans[zIn[0]];
517 if( v>=0 ){
518 x[k++] = v;
519 if( k==4 ){
520 zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
521 zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
522 zData[j++] = ((x[2]<<6) & 0xc0) | (x[3] & 0x3f);
523 k = 0;
524 }
525 }
526 }
527 if( k>=2 ){
528 zData[j++] = ((x[0]<<2) & 0xfc) | ((x[1]>>4) & 0x03);
529 if( k==3 ){
530 zData[j++] = ((x[1]<<4) & 0xf0) | ((x[2]>>2) & 0x0f);
531 }
532 }
533 zData[j] = 0;
534 *pnByte = j;
535 }
536
537
538 /*
539 ** This function treats its input as a base-64 string and returns the
540 ** decoded value of that string. Characters of input that are not
541 ** valid base-64 characters (such as spaces and newlines) are ignored.
@@ -504,46 +544,14 @@
544 **
545 ** The number of bytes decoded is returned in *pnByte
546 */
547 char *decode64(const char *z64, int *pnByte){
548 char *zData;
549 int n64 = (int)strlen(z64);
 
 
 
 
 
 
 
 
 
 
 
550 while( n64>0 && z64[n64-1]=='=' ) n64--;
551 zData = fossil_malloc( (n64*3)/4 + 4 );
552 decodeBase64(z64, pnByte, zData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553 return zData;
554 }
555
556 /*
557 ** COMMAND: test-decode64
@@ -554,11 +562,11 @@
562 char *z;
563 int i, n;
564 for(i=2; i<g.argc; i++){
565 z = decode64(g.argv[i], &n);
566 fossil_print("%d: %s\n", n, z);
567 fossil_free(z);
568 }
569 }
570
571 /*
572 ** The base-16 encoding using the following characters:
@@ -654,10 +662,35 @@
662 while( *z && n-- ){
663 *z = zEncode[zDecode[(*z)&0x7f]&0x1f];
664 z++;
665 }
666 }
667
668 /*
669 ** Decode a string encoded using "quoted-printable".
670 **
671 ** (1) "=" followed by two hex digits becomes a single
672 ** byte specified by the two digits
673 **
674 ** The decoding is done in-place.
675 */
676 void decodeQuotedPrintable(char *z, int *pnByte){
677 int i, j, c;
678 for(i=j=0; (c = z[i])!=0; i++){
679 if( c=='=' ){
680 if( z[i+1]!='\r' ){
681 decode16((unsigned char*)&z[i+1], (unsigned char*)&z[j], 2);
682 j++;
683 }
684 i += 2;
685 }else{
686 z[j++] = c;
687 }
688 }
689 if( pnByte ) *pnByte = j;
690 z[j] = 0;
691 }
692
693 /* Randomness used for XOR-ing by the obscure() and unobscure() routines */
694 static const unsigned char aObscurer[16] = {
695 0xa7, 0x21, 0x31, 0xe3, 0x2a, 0x50, 0x2c, 0x86,
696 0x4c, 0xa4, 0x52, 0x25, 0xff, 0x49, 0x35, 0x85
697
+20 -1
--- src/webmail.c
+++ src/webmail.c
@@ -267,11 +267,30 @@
267267
fossil_print("%3d: %s\n", i, p->azHdr[i]);
268268
}
269269
for(i=0; i<p->nBody; i++){
270270
fossil_print("\nBODY %d mime \"%s\" encoding %d:\n",
271271
i, p->aBody[i].zMimetype, p->aBody[i].encoding);
272
- fossil_print("%s\n", p->aBody[i].zContent);
272
+ switch( p->aBody[i].encoding ){
273
+ case EMAILENC_B64: {
274
+ int n = 0;
275
+ decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent);
276
+ fossil_print("%s", p->aBody[i].zContent);
277
+ if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n");
278
+ break;
279
+ }
280
+ case EMAILENC_QUOTED: {
281
+ int n = 0;
282
+ decodeQuotedPrintable(p->aBody[i].zContent, &n);
283
+ fossil_print("%s", p->aBody[i].zContent);
284
+ if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n");
285
+ break;
286
+ }
287
+ default: {
288
+ fossil_print("%s\n", p->aBody[i].zContent);
289
+ break;
290
+ }
291
+ }
273292
}
274293
emailtoc_free(p);
275294
blob_reset(&email);
276295
}
277296
278297
--- src/webmail.c
+++ src/webmail.c
@@ -267,11 +267,30 @@
267 fossil_print("%3d: %s\n", i, p->azHdr[i]);
268 }
269 for(i=0; i<p->nBody; i++){
270 fossil_print("\nBODY %d mime \"%s\" encoding %d:\n",
271 i, p->aBody[i].zMimetype, p->aBody[i].encoding);
272 fossil_print("%s\n", p->aBody[i].zContent);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273 }
274 emailtoc_free(p);
275 blob_reset(&email);
276 }
277
278
--- src/webmail.c
+++ src/webmail.c
@@ -267,11 +267,30 @@
267 fossil_print("%3d: %s\n", i, p->azHdr[i]);
268 }
269 for(i=0; i<p->nBody; i++){
270 fossil_print("\nBODY %d mime \"%s\" encoding %d:\n",
271 i, p->aBody[i].zMimetype, p->aBody[i].encoding);
272 switch( p->aBody[i].encoding ){
273 case EMAILENC_B64: {
274 int n = 0;
275 decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent);
276 fossil_print("%s", p->aBody[i].zContent);
277 if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n");
278 break;
279 }
280 case EMAILENC_QUOTED: {
281 int n = 0;
282 decodeQuotedPrintable(p->aBody[i].zContent, &n);
283 fossil_print("%s", p->aBody[i].zContent);
284 if( n && p->aBody[i].zContent[n-1]!='\n' ) fossil_print("\n");
285 break;
286 }
287 default: {
288 fossil_print("%s\n", p->aBody[i].zContent);
289 break;
290 }
291 }
292 }
293 emailtoc_free(p);
294 blob_reset(&email);
295 }
296
297

Keyboard Shortcuts

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