Fossil SCM

New "Normal" mode for viewing email messages in webmail.

drh 2018-07-14 19:40 webmail
Commit 3ddc8817137f74459df37513567c82aeeddf19dddafa8c1e19dc043d3997def9
2 files changed +1 -1 +59 -9
+1 -1
--- src/smtp.c
+++ src/smtp.c
@@ -652,11 +652,11 @@
652652
@ euser TEXT, -- User who received this email
653653
@ edate INT, -- Date received. Seconds since 1970
654654
@ efrom TEXT, -- Who is the email from
655655
@ emsgid INT, -- Raw email text
656656
@ ets INT, -- Transcript of the receiving SMTP session
657
-@ estate INT, -- 0: Unread, 1: read, 2: trash
657
+@ estate INT, -- 0: Unread, 1: read, 2: trash 3: sent
658658
@ esubject TEXT, -- Subject line for display
659659
@ etags TEXT -- zero or more tags
660660
@ );
661661
@
662662
@ -- Information on how to deliver incoming email.
663663
--- src/smtp.c
+++ src/smtp.c
@@ -652,11 +652,11 @@
652 @ euser TEXT, -- User who received this email
653 @ edate INT, -- Date received. Seconds since 1970
654 @ efrom TEXT, -- Who is the email from
655 @ emsgid INT, -- Raw email text
656 @ ets INT, -- Transcript of the receiving SMTP session
657 @ estate INT, -- 0: Unread, 1: read, 2: trash
658 @ esubject TEXT, -- Subject line for display
659 @ etags TEXT -- zero or more tags
660 @ );
661 @
662 @ -- Information on how to deliver incoming email.
663
--- src/smtp.c
+++ src/smtp.c
@@ -652,11 +652,11 @@
652 @ euser TEXT, -- User who received this email
653 @ edate INT, -- Date received. Seconds since 1970
654 @ efrom TEXT, -- Who is the email from
655 @ emsgid INT, -- Raw email text
656 @ ets INT, -- Transcript of the receiving SMTP session
657 @ estate INT, -- 0: Unread, 1: read, 2: trash 3: sent
658 @ esubject TEXT, -- Subject line for display
659 @ etags TEXT -- zero or more tags
660 @ );
661 @
662 @ -- Information on how to deliver incoming email.
663
+59 -9
--- src/webmail.c
+++ src/webmail.c
@@ -352,10 +352,38 @@
352352
}
353353
}
354354
emailtoc_free(p);
355355
blob_reset(&email);
356356
}
357
+
358
+/*
359
+** Add the select/option box to the timeline submenu that shows
360
+** the various email message formats.
361
+*/
362
+static void webmail_f_submenu(void){
363
+ static const char *az[] = {
364
+ "0", "Normal",
365
+ "1", "Decoded",
366
+ "2", "Raw",
367
+ };
368
+ style_submenu_multichoice("f", sizeof(az)/(2*sizeof(az[0])), az, 0);
369
+}
370
+
371
+/*
372
+** If the first N characters of z[] are the name of a header field
373
+** that should be shown in "Normal" mode, then return 1.
374
+*/
375
+static int webmail_normal_header(const char *z, int N){
376
+ static const char *az[] = {
377
+ "To", "Cc", "Bcc", "Date", "From", "Subject",
378
+ };
379
+ int i;
380
+ for(i=0; i<sizeof(az)/sizeof(az[0]); i++){
381
+ if( sqlite3_strnicmp(z, az[i], N)==0 ) return 1;
382
+ }
383
+ return 0;
384
+}
357385
358386
/*
359387
** Paint a page showing a single email message
360388
*/
361389
static void webmail_show_one_message(
@@ -366,10 +394,11 @@
366394
Blob sql;
367395
Stmt q;
368396
int eState = -1;
369397
char zENum[30];
370398
style_submenu_element("Index", "%s", url_render(pUrl,"id",0,0,0));
399
+ webmail_f_submenu();
371400
blob_init(&sql, 0, 0);
372401
db_begin_transaction();
373402
blob_append_sql(&sql,
374403
"SELECT decompress(etxt), estate"
375404
" FROM emailblob, emailbox"
@@ -382,23 +411,21 @@
382411
style_header("Message %d",emailid);
383412
if( db_step(&q)==SQLITE_ROW ){
384413
Blob msg = db_column_text_as_blob(&q, 0);
385414
int eFormat = atoi(PD("f","0"));
386415
eState = db_column_int(&q, 1);
387
- url_add_parameter(pUrl, "id", P("id"));
388
- if( eFormat==1 ){
416
+ if( eFormat==2 ){
389417
@ <pre>%h(db_column_text(&q, 0))</pre>
390
- style_submenu_element("Decoded", "%s", url_render(pUrl,"f",0,0,0));
391418
}else{
392419
EmailToc *p = emailtoc_from_email(&msg);
393420
int i, j;
394
- style_submenu_element("Raw", "%s", url_render(pUrl,"f","1",0,0));
395421
@ <p>
396422
for(i=0; i<p->nHdr; i++){
397423
char *z = p->azHdr[i];
398424
email_hdr_unfold(z);
399425
for(j=0; z[j] && z[j]!=':'; j++){}
426
+ if( eFormat==0 && !webmail_normal_header(z, j) ) continue;
400427
if( z[j]!=':' ){
401428
@ %h(z)<br>
402429
}else{
403430
z[j] = 0;
404431
@ <b>%h(z):</b> %h(z+j+1)<br>
@@ -408,11 +435,16 @@
408435
@ <hr><b>Messsage Body #%d(i): %h(p->aBody[i].zMimetype) \
409436
if( p->aBody[i].zFilename ){
410437
@ "%h(p->aBody[i].zFilename)"
411438
}
412439
@ </b>
413
- if( strncmp(p->aBody[i].zMimetype, "text/", 5)!=0 ) continue;
440
+ if( eFormat==0 ){
441
+ if( strncmp(p->aBody[i].zMimetype, "text/plain", 10)!=0 ) continue;
442
+ if( p->aBody[i].zFilename ) continue;
443
+ }else{
444
+ if( strncmp(p->aBody[i].zMimetype, "text/", 5)!=0 ) continue;
445
+ }
414446
switch( p->aBody[i].encoding ){
415447
case EMAILENC_B64: {
416448
int n = 0;
417449
decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent);
418450
break;
@@ -452,10 +484,14 @@
452484
style_submenu_element("Delete", "%s",
453485
url_render(pUrl,"trash","1",zENum,"1"));
454486
style_submenu_element("Mark As Unread", "%s",
455487
url_render(pUrl,"unread","1",zENum,"1"));
456488
}
489
+ if( eState==3 ){
490
+ style_submenu_element("Delete", "%s",
491
+ url_render(pUrl,"trash","1",zENum,"1"));
492
+ }
457493
458494
db_end_transaction(0);
459495
style_footer();
460496
return;
461497
}
@@ -463,21 +499,27 @@
463499
/*
464500
** Scan the query parameters looking for parameters with name of the
465501
** form "eN" where N is an integer. For all such integers, change
466502
** the state of every emailbox entry with ebid==N to eStateNew provided
467503
** that either zUser is NULL or matches.
504
+**
505
+** Or if eNewState==99, then delete the entries.
468506
*/
469507
static void webmail_change_state(int eNewState, const char *zUser){
470508
Blob sql;
471509
int sep = '(';
472510
int i;
473511
const char *zName;
474512
int n;
475513
if( !cgi_csrf_safe(0) ) return;
476514
blob_init(&sql, 0, 0);
477
- blob_append_sql(&sql, "UPDATE emailbox SET estate=%d WHERE ebid IN ",
478
- eNewState);
515
+ if( eNewState==99 ){
516
+ blob_append_sql(&sql, "DELETE FROM emailbox WHERE estate==2 AND ebid IN ");
517
+ }else{
518
+ blob_append_sql(&sql, "UPDATE emailbox SET estate=%d WHERE ebid IN ",
519
+ eNewState);
520
+ }
479521
for(i=0; (zName = cgi_parameter_name(i))!=0; i++){
480522
if( zName[0]!='e' ) continue;
481523
if( !fossil_isdigit(zName[1]) ) continue;
482524
n = atoi(zName+1);
483525
blob_append_sql(&sql, "%c%d", sep, n);
@@ -502,11 +544,12 @@
502544
static void webmail_d_submenu(void){
503545
static const char *az[] = {
504546
"0", "InBox",
505547
"1", "Unread",
506548
"2", "Trash",
507
- "3", "Everything",
549
+ "3", "Sent",
550
+ "4", "Everything",
508551
};
509552
style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0);
510553
}
511554
512555
/*
@@ -576,10 +619,11 @@
576619
webmail_d_submenu();
577620
db_begin_transaction();
578621
if( P("trash")!=0 ) webmail_change_state(2,zUser);
579622
if( P("unread")!=0 ) webmail_change_state(0,zUser);
580623
if( P("read")!=0 ) webmail_change_state(1,zUser);
624
+ if( P("purge")!=0 ) webmail_change_state(99,zUser);
581625
blob_init(&sql, 0, 0);
582626
blob_append_sql(&sql,
583627
"CREATE TEMP TABLE tmbox AS "
584628
"SELECT ebid," /* 0 */
585629
" efrom," /* 1 */
@@ -601,11 +645,15 @@
601645
}
602646
case 2: { /* Trashcan only */
603647
blob_append_sql(&sql, " WHERE estate=2");
604648
break;
605649
}
606
- case 3: { /* Everything */
650
+ case 3: { /* Outgoing email only */
651
+ blob_append_sql(&sql, " WHERE estate=3");
652
+ break;
653
+ }
654
+ case 4: { /* Everything */
607655
blob_append_sql(&sql, " WHERE 1");
608656
break;
609657
}
610658
}
611659
if( showAll ){
@@ -635,17 +683,19 @@
635683
@ <form action="%R/webmail" method="POST">
636684
@ <table border="0" width="100%%">
637685
@ <tr><td align="left">
638686
if( d==2 ){
639687
@ <input type="submit" name="read" value="Undelete">
688
+ @ <input type="submit" name="purge" value="Delete Permanently">
640689
}else{
641690
@ <input type="submit" name="trash", value="Delete">
642691
if( d!=1 ){
643692
@ <input type="submit" name="unread" value="Mark as unread">
644693
}
645694
@ <input type="submit" name="read" value="Mark as read">
646695
}
696
+ @ <a href="%s(url_render(&url,0,0,0,0))">refresh</a>
647697
@ </td><td align="right">
648698
if( pg>0 ){
649699
sqlite3_snprintf(sizeof(zPPg), zPPg, "%d", pg-1);
650700
@ <a href="%s(url_render(&url,"pg",zPPg,0,0))">&lt; Newer</a>&nbsp;&nbsp;
651701
}
652702
--- src/webmail.c
+++ src/webmail.c
@@ -352,10 +352,38 @@
352 }
353 }
354 emailtoc_free(p);
355 blob_reset(&email);
356 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
358 /*
359 ** Paint a page showing a single email message
360 */
361 static void webmail_show_one_message(
@@ -366,10 +394,11 @@
366 Blob sql;
367 Stmt q;
368 int eState = -1;
369 char zENum[30];
370 style_submenu_element("Index", "%s", url_render(pUrl,"id",0,0,0));
 
371 blob_init(&sql, 0, 0);
372 db_begin_transaction();
373 blob_append_sql(&sql,
374 "SELECT decompress(etxt), estate"
375 " FROM emailblob, emailbox"
@@ -382,23 +411,21 @@
382 style_header("Message %d",emailid);
383 if( db_step(&q)==SQLITE_ROW ){
384 Blob msg = db_column_text_as_blob(&q, 0);
385 int eFormat = atoi(PD("f","0"));
386 eState = db_column_int(&q, 1);
387 url_add_parameter(pUrl, "id", P("id"));
388 if( eFormat==1 ){
389 @ <pre>%h(db_column_text(&q, 0))</pre>
390 style_submenu_element("Decoded", "%s", url_render(pUrl,"f",0,0,0));
391 }else{
392 EmailToc *p = emailtoc_from_email(&msg);
393 int i, j;
394 style_submenu_element("Raw", "%s", url_render(pUrl,"f","1",0,0));
395 @ <p>
396 for(i=0; i<p->nHdr; i++){
397 char *z = p->azHdr[i];
398 email_hdr_unfold(z);
399 for(j=0; z[j] && z[j]!=':'; j++){}
 
400 if( z[j]!=':' ){
401 @ %h(z)<br>
402 }else{
403 z[j] = 0;
404 @ <b>%h(z):</b> %h(z+j+1)<br>
@@ -408,11 +435,16 @@
408 @ <hr><b>Messsage Body #%d(i): %h(p->aBody[i].zMimetype) \
409 if( p->aBody[i].zFilename ){
410 @ "%h(p->aBody[i].zFilename)"
411 }
412 @ </b>
413 if( strncmp(p->aBody[i].zMimetype, "text/", 5)!=0 ) continue;
 
 
 
 
 
414 switch( p->aBody[i].encoding ){
415 case EMAILENC_B64: {
416 int n = 0;
417 decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent);
418 break;
@@ -452,10 +484,14 @@
452 style_submenu_element("Delete", "%s",
453 url_render(pUrl,"trash","1",zENum,"1"));
454 style_submenu_element("Mark As Unread", "%s",
455 url_render(pUrl,"unread","1",zENum,"1"));
456 }
 
 
 
 
457
458 db_end_transaction(0);
459 style_footer();
460 return;
461 }
@@ -463,21 +499,27 @@
463 /*
464 ** Scan the query parameters looking for parameters with name of the
465 ** form "eN" where N is an integer. For all such integers, change
466 ** the state of every emailbox entry with ebid==N to eStateNew provided
467 ** that either zUser is NULL or matches.
 
 
468 */
469 static void webmail_change_state(int eNewState, const char *zUser){
470 Blob sql;
471 int sep = '(';
472 int i;
473 const char *zName;
474 int n;
475 if( !cgi_csrf_safe(0) ) return;
476 blob_init(&sql, 0, 0);
477 blob_append_sql(&sql, "UPDATE emailbox SET estate=%d WHERE ebid IN ",
478 eNewState);
 
 
 
 
479 for(i=0; (zName = cgi_parameter_name(i))!=0; i++){
480 if( zName[0]!='e' ) continue;
481 if( !fossil_isdigit(zName[1]) ) continue;
482 n = atoi(zName+1);
483 blob_append_sql(&sql, "%c%d", sep, n);
@@ -502,11 +544,12 @@
502 static void webmail_d_submenu(void){
503 static const char *az[] = {
504 "0", "InBox",
505 "1", "Unread",
506 "2", "Trash",
507 "3", "Everything",
 
508 };
509 style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0);
510 }
511
512 /*
@@ -576,10 +619,11 @@
576 webmail_d_submenu();
577 db_begin_transaction();
578 if( P("trash")!=0 ) webmail_change_state(2,zUser);
579 if( P("unread")!=0 ) webmail_change_state(0,zUser);
580 if( P("read")!=0 ) webmail_change_state(1,zUser);
 
581 blob_init(&sql, 0, 0);
582 blob_append_sql(&sql,
583 "CREATE TEMP TABLE tmbox AS "
584 "SELECT ebid," /* 0 */
585 " efrom," /* 1 */
@@ -601,11 +645,15 @@
601 }
602 case 2: { /* Trashcan only */
603 blob_append_sql(&sql, " WHERE estate=2");
604 break;
605 }
606 case 3: { /* Everything */
 
 
 
 
607 blob_append_sql(&sql, " WHERE 1");
608 break;
609 }
610 }
611 if( showAll ){
@@ -635,17 +683,19 @@
635 @ <form action="%R/webmail" method="POST">
636 @ <table border="0" width="100%%">
637 @ <tr><td align="left">
638 if( d==2 ){
639 @ <input type="submit" name="read" value="Undelete">
 
640 }else{
641 @ <input type="submit" name="trash", value="Delete">
642 if( d!=1 ){
643 @ <input type="submit" name="unread" value="Mark as unread">
644 }
645 @ <input type="submit" name="read" value="Mark as read">
646 }
 
647 @ </td><td align="right">
648 if( pg>0 ){
649 sqlite3_snprintf(sizeof(zPPg), zPPg, "%d", pg-1);
650 @ <a href="%s(url_render(&url,"pg",zPPg,0,0))">&lt; Newer</a>&nbsp;&nbsp;
651 }
652
--- src/webmail.c
+++ src/webmail.c
@@ -352,10 +352,38 @@
352 }
353 }
354 emailtoc_free(p);
355 blob_reset(&email);
356 }
357
358 /*
359 ** Add the select/option box to the timeline submenu that shows
360 ** the various email message formats.
361 */
362 static void webmail_f_submenu(void){
363 static const char *az[] = {
364 "0", "Normal",
365 "1", "Decoded",
366 "2", "Raw",
367 };
368 style_submenu_multichoice("f", sizeof(az)/(2*sizeof(az[0])), az, 0);
369 }
370
371 /*
372 ** If the first N characters of z[] are the name of a header field
373 ** that should be shown in "Normal" mode, then return 1.
374 */
375 static int webmail_normal_header(const char *z, int N){
376 static const char *az[] = {
377 "To", "Cc", "Bcc", "Date", "From", "Subject",
378 };
379 int i;
380 for(i=0; i<sizeof(az)/sizeof(az[0]); i++){
381 if( sqlite3_strnicmp(z, az[i], N)==0 ) return 1;
382 }
383 return 0;
384 }
385
386 /*
387 ** Paint a page showing a single email message
388 */
389 static void webmail_show_one_message(
@@ -366,10 +394,11 @@
394 Blob sql;
395 Stmt q;
396 int eState = -1;
397 char zENum[30];
398 style_submenu_element("Index", "%s", url_render(pUrl,"id",0,0,0));
399 webmail_f_submenu();
400 blob_init(&sql, 0, 0);
401 db_begin_transaction();
402 blob_append_sql(&sql,
403 "SELECT decompress(etxt), estate"
404 " FROM emailblob, emailbox"
@@ -382,23 +411,21 @@
411 style_header("Message %d",emailid);
412 if( db_step(&q)==SQLITE_ROW ){
413 Blob msg = db_column_text_as_blob(&q, 0);
414 int eFormat = atoi(PD("f","0"));
415 eState = db_column_int(&q, 1);
416 if( eFormat==2 ){
 
417 @ <pre>%h(db_column_text(&q, 0))</pre>
 
418 }else{
419 EmailToc *p = emailtoc_from_email(&msg);
420 int i, j;
 
421 @ <p>
422 for(i=0; i<p->nHdr; i++){
423 char *z = p->azHdr[i];
424 email_hdr_unfold(z);
425 for(j=0; z[j] && z[j]!=':'; j++){}
426 if( eFormat==0 && !webmail_normal_header(z, j) ) continue;
427 if( z[j]!=':' ){
428 @ %h(z)<br>
429 }else{
430 z[j] = 0;
431 @ <b>%h(z):</b> %h(z+j+1)<br>
@@ -408,11 +435,16 @@
435 @ <hr><b>Messsage Body #%d(i): %h(p->aBody[i].zMimetype) \
436 if( p->aBody[i].zFilename ){
437 @ "%h(p->aBody[i].zFilename)"
438 }
439 @ </b>
440 if( eFormat==0 ){
441 if( strncmp(p->aBody[i].zMimetype, "text/plain", 10)!=0 ) continue;
442 if( p->aBody[i].zFilename ) continue;
443 }else{
444 if( strncmp(p->aBody[i].zMimetype, "text/", 5)!=0 ) continue;
445 }
446 switch( p->aBody[i].encoding ){
447 case EMAILENC_B64: {
448 int n = 0;
449 decodeBase64(p->aBody[i].zContent, &n, p->aBody[i].zContent);
450 break;
@@ -452,10 +484,14 @@
484 style_submenu_element("Delete", "%s",
485 url_render(pUrl,"trash","1",zENum,"1"));
486 style_submenu_element("Mark As Unread", "%s",
487 url_render(pUrl,"unread","1",zENum,"1"));
488 }
489 if( eState==3 ){
490 style_submenu_element("Delete", "%s",
491 url_render(pUrl,"trash","1",zENum,"1"));
492 }
493
494 db_end_transaction(0);
495 style_footer();
496 return;
497 }
@@ -463,21 +499,27 @@
499 /*
500 ** Scan the query parameters looking for parameters with name of the
501 ** form "eN" where N is an integer. For all such integers, change
502 ** the state of every emailbox entry with ebid==N to eStateNew provided
503 ** that either zUser is NULL or matches.
504 **
505 ** Or if eNewState==99, then delete the entries.
506 */
507 static void webmail_change_state(int eNewState, const char *zUser){
508 Blob sql;
509 int sep = '(';
510 int i;
511 const char *zName;
512 int n;
513 if( !cgi_csrf_safe(0) ) return;
514 blob_init(&sql, 0, 0);
515 if( eNewState==99 ){
516 blob_append_sql(&sql, "DELETE FROM emailbox WHERE estate==2 AND ebid IN ");
517 }else{
518 blob_append_sql(&sql, "UPDATE emailbox SET estate=%d WHERE ebid IN ",
519 eNewState);
520 }
521 for(i=0; (zName = cgi_parameter_name(i))!=0; i++){
522 if( zName[0]!='e' ) continue;
523 if( !fossil_isdigit(zName[1]) ) continue;
524 n = atoi(zName+1);
525 blob_append_sql(&sql, "%c%d", sep, n);
@@ -502,11 +544,12 @@
544 static void webmail_d_submenu(void){
545 static const char *az[] = {
546 "0", "InBox",
547 "1", "Unread",
548 "2", "Trash",
549 "3", "Sent",
550 "4", "Everything",
551 };
552 style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0);
553 }
554
555 /*
@@ -576,10 +619,11 @@
619 webmail_d_submenu();
620 db_begin_transaction();
621 if( P("trash")!=0 ) webmail_change_state(2,zUser);
622 if( P("unread")!=0 ) webmail_change_state(0,zUser);
623 if( P("read")!=0 ) webmail_change_state(1,zUser);
624 if( P("purge")!=0 ) webmail_change_state(99,zUser);
625 blob_init(&sql, 0, 0);
626 blob_append_sql(&sql,
627 "CREATE TEMP TABLE tmbox AS "
628 "SELECT ebid," /* 0 */
629 " efrom," /* 1 */
@@ -601,11 +645,15 @@
645 }
646 case 2: { /* Trashcan only */
647 blob_append_sql(&sql, " WHERE estate=2");
648 break;
649 }
650 case 3: { /* Outgoing email only */
651 blob_append_sql(&sql, " WHERE estate=3");
652 break;
653 }
654 case 4: { /* Everything */
655 blob_append_sql(&sql, " WHERE 1");
656 break;
657 }
658 }
659 if( showAll ){
@@ -635,17 +683,19 @@
683 @ <form action="%R/webmail" method="POST">
684 @ <table border="0" width="100%%">
685 @ <tr><td align="left">
686 if( d==2 ){
687 @ <input type="submit" name="read" value="Undelete">
688 @ <input type="submit" name="purge" value="Delete Permanently">
689 }else{
690 @ <input type="submit" name="trash", value="Delete">
691 if( d!=1 ){
692 @ <input type="submit" name="unread" value="Mark as unread">
693 }
694 @ <input type="submit" name="read" value="Mark as read">
695 }
696 @ <a href="%s(url_render(&url,0,0,0,0))">refresh</a>
697 @ </td><td align="right">
698 if( pg>0 ){
699 sqlite3_snprintf(sizeof(zPPg), zPPg, "%d", pg-1);
700 @ <a href="%s(url_render(&url,"pg",zPPg,0,0))">&lt; Newer</a>&nbsp;&nbsp;
701 }
702

Keyboard Shortcuts

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