Fossil SCM

Add the --logdir option to the "fossil pop3d" command. Fix some issues with POP3 reply formatting.

drh 2018-07-18 01:40 trunk
Commit 38165f3764caa8e51ac173c9121378a25f477619b2f222f1526db672e05a5742
3 files changed +2 -15 +33 -5 +61 -23
+2 -15
--- src/email.c
+++ src/email.c
@@ -364,23 +364,10 @@
364364
iCol += 3;
365365
}
366366
}
367367
}
368368
369
-/*
370
-** Come up with a unique filename in the zDir directory.
371
-**
372
-** Space to hold the filename is obtained from mprintf() and must
373
-** be freed using fossil_free() by the caller.
374
-*/
375
-static char *emailTempFilename(const char *zDir){
376
- char *zFile = db_text(0,
377
- "SELECT %Q||strftime('/%%Y%%m%%d%%H%%M%%S-','now')||hex(randomblob(8))",
378
- zDir);
379
- return zFile;
380
-}
381
-
382369
#if defined(_WIN32) || defined(WIN32)
383370
# undef popen
384371
# define popen _popen
385372
# undef pclose
386373
# define pclose _pclose
@@ -748,11 +735,11 @@
748735
fclose(out);
749736
}else{
750737
emailerError(p, "Could not open output pipe \"%s\"", p->zCmd);
751738
}
752739
}else if( p->zDir ){
753
- char *zFile = emailTempFilename(p->zDir);
740
+ char *zFile = file_time_tempname(p->zDir, ".email");
754741
blob_write_to_file(&all, zFile);
755742
fossil_free(zFile);
756743
}else if( p->pSmtp ){
757744
char **azTo = 0;
758745
int nTo = 0;
@@ -904,11 +891,11 @@
904891
if( g.argc!=3 && g.argc!=4 ){
905892
usage("inbound [FILE]");
906893
}
907894
blob_read_from_file(&email, g.argc==3 ? "-" : g.argv[3], ExtFILE);
908895
if( zInboundDir[0] ){
909
- char *zFN = emailTempFilename(zInboundDir);
896
+ char *zFN = file_time_tempname(zInboundDir,".email");
910897
blob_write_to_file(&email, zFN);
911898
fossil_free(zFN);
912899
}
913900
email_receive(&email);
914901
}else
915902
--- src/email.c
+++ src/email.c
@@ -364,23 +364,10 @@
364 iCol += 3;
365 }
366 }
367 }
368
369 /*
370 ** Come up with a unique filename in the zDir directory.
371 **
372 ** Space to hold the filename is obtained from mprintf() and must
373 ** be freed using fossil_free() by the caller.
374 */
375 static char *emailTempFilename(const char *zDir){
376 char *zFile = db_text(0,
377 "SELECT %Q||strftime('/%%Y%%m%%d%%H%%M%%S-','now')||hex(randomblob(8))",
378 zDir);
379 return zFile;
380 }
381
382 #if defined(_WIN32) || defined(WIN32)
383 # undef popen
384 # define popen _popen
385 # undef pclose
386 # define pclose _pclose
@@ -748,11 +735,11 @@
748 fclose(out);
749 }else{
750 emailerError(p, "Could not open output pipe \"%s\"", p->zCmd);
751 }
752 }else if( p->zDir ){
753 char *zFile = emailTempFilename(p->zDir);
754 blob_write_to_file(&all, zFile);
755 fossil_free(zFile);
756 }else if( p->pSmtp ){
757 char **azTo = 0;
758 int nTo = 0;
@@ -904,11 +891,11 @@
904 if( g.argc!=3 && g.argc!=4 ){
905 usage("inbound [FILE]");
906 }
907 blob_read_from_file(&email, g.argc==3 ? "-" : g.argv[3], ExtFILE);
908 if( zInboundDir[0] ){
909 char *zFN = emailTempFilename(zInboundDir);
910 blob_write_to_file(&email, zFN);
911 fossil_free(zFN);
912 }
913 email_receive(&email);
914 }else
915
--- src/email.c
+++ src/email.c
@@ -364,23 +364,10 @@
364 iCol += 3;
365 }
366 }
367 }
368
 
 
 
 
 
 
 
 
 
 
 
 
 
369 #if defined(_WIN32) || defined(WIN32)
370 # undef popen
371 # define popen _popen
372 # undef pclose
373 # define pclose _pclose
@@ -748,11 +735,11 @@
735 fclose(out);
736 }else{
737 emailerError(p, "Could not open output pipe \"%s\"", p->zCmd);
738 }
739 }else if( p->zDir ){
740 char *zFile = file_time_tempname(p->zDir, ".email");
741 blob_write_to_file(&all, zFile);
742 fossil_free(zFile);
743 }else if( p->pSmtp ){
744 char **azTo = 0;
745 int nTo = 0;
@@ -904,11 +891,11 @@
891 if( g.argc!=3 && g.argc!=4 ){
892 usage("inbound [FILE]");
893 }
894 blob_read_from_file(&email, g.argc==3 ? "-" : g.argv[3], ExtFILE);
895 if( zInboundDir[0] ){
896 char *zFN = file_time_tempname(zInboundDir,".email");
897 blob_write_to_file(&email, zFN);
898 fossil_free(zFN);
899 }
900 email_receive(&email);
901 }else
902
+33 -5
--- src/file.c
+++ src/file.c
@@ -22,10 +22,11 @@
2222
#include <sys/stat.h>
2323
#include <unistd.h>
2424
#include <stdio.h>
2525
#include <string.h>
2626
#include <errno.h>
27
+#include <time.h>
2728
#include "file.h"
2829
2930
/*
3031
** On Windows, include the Platform SDK header file.
3132
*/
@@ -1468,24 +1469,51 @@
14681469
#else
14691470
fossil_path_free((char *)azDirs[0]);
14701471
#endif
14711472
}
14721473
1474
+/*
1475
+** Compute a temporary filename in zDir. The filename is based on
1476
+** the current time.
1477
+*/
1478
+char *file_time_tempname(const char *zDir, const char *zSuffix){
1479
+ struct tm *tm;
1480
+ unsigned int r;
1481
+ static unsigned int cnt = 0;
1482
+ time_t t;
1483
+ t = time(0);
1484
+ tm = gmtime(&t);
1485
+ sqlite3_randomness(sizeof(r), &r);
1486
+ return mprintf("%s/%04d%02d%02d%02d%02d%02d%04d%06d%s",
1487
+ zDir, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
1488
+ tm->tm_hour, tm->tm_min, tm->tm_sec, cnt++, r%1000000, zSuffix);
1489
+}
1490
+
14731491
14741492
/*
14751493
** COMMAND: test-tempname
1476
-** Usage: fossil test-name BASENAME ...
1494
+** Usage: fossil test-name [--time SUFFIX] BASENAME ...
14771495
**
1478
-** Generate temporary filenames derived from BASENAME
1496
+** Generate temporary filenames derived from BASENAME. Use the --time
1497
+** option to generate temp names based on the time of day.
14791498
*/
14801499
void file_test_tempname(void){
14811500
int i;
1501
+ char *zSuffix = find_option("time",0,1);
14821502
Blob x = BLOB_INITIALIZER;
1503
+ char *z;
1504
+ verify_all_options();
14831505
for(i=2; i<g.argc; i++){
1484
- file_tempname(&x, g.argv[i]);
1485
- fossil_print("%s\n", blob_str(&x));
1486
- blob_reset(&x);
1506
+ if( zSuffix ){
1507
+ z = file_time_tempname(g.argv[i], zSuffix);
1508
+ fossil_print("%s\n", z);
1509
+ fossil_free(z);
1510
+ }else{
1511
+ file_tempname(&x, g.argv[i]);
1512
+ fossil_print("%s\n", blob_str(&x));
1513
+ blob_reset(&x);
1514
+ }
14871515
}
14881516
}
14891517
14901518
14911519
/*
14921520
--- src/file.c
+++ src/file.c
@@ -22,10 +22,11 @@
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
 
27 #include "file.h"
28
29 /*
30 ** On Windows, include the Platform SDK header file.
31 */
@@ -1468,24 +1469,51 @@
1468 #else
1469 fossil_path_free((char *)azDirs[0]);
1470 #endif
1471 }
1472
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1473
1474 /*
1475 ** COMMAND: test-tempname
1476 ** Usage: fossil test-name BASENAME ...
1477 **
1478 ** Generate temporary filenames derived from BASENAME
 
1479 */
1480 void file_test_tempname(void){
1481 int i;
 
1482 Blob x = BLOB_INITIALIZER;
 
 
1483 for(i=2; i<g.argc; i++){
1484 file_tempname(&x, g.argv[i]);
1485 fossil_print("%s\n", blob_str(&x));
1486 blob_reset(&x);
 
 
 
 
 
 
1487 }
1488 }
1489
1490
1491 /*
1492
--- src/file.c
+++ src/file.c
@@ -22,10 +22,11 @@
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <time.h>
28 #include "file.h"
29
30 /*
31 ** On Windows, include the Platform SDK header file.
32 */
@@ -1468,24 +1469,51 @@
1469 #else
1470 fossil_path_free((char *)azDirs[0]);
1471 #endif
1472 }
1473
1474 /*
1475 ** Compute a temporary filename in zDir. The filename is based on
1476 ** the current time.
1477 */
1478 char *file_time_tempname(const char *zDir, const char *zSuffix){
1479 struct tm *tm;
1480 unsigned int r;
1481 static unsigned int cnt = 0;
1482 time_t t;
1483 t = time(0);
1484 tm = gmtime(&t);
1485 sqlite3_randomness(sizeof(r), &r);
1486 return mprintf("%s/%04d%02d%02d%02d%02d%02d%04d%06d%s",
1487 zDir, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
1488 tm->tm_hour, tm->tm_min, tm->tm_sec, cnt++, r%1000000, zSuffix);
1489 }
1490
1491
1492 /*
1493 ** COMMAND: test-tempname
1494 ** Usage: fossil test-name [--time SUFFIX] BASENAME ...
1495 **
1496 ** Generate temporary filenames derived from BASENAME. Use the --time
1497 ** option to generate temp names based on the time of day.
1498 */
1499 void file_test_tempname(void){
1500 int i;
1501 char *zSuffix = find_option("time",0,1);
1502 Blob x = BLOB_INITIALIZER;
1503 char *z;
1504 verify_all_options();
1505 for(i=2; i<g.argc; i++){
1506 if( zSuffix ){
1507 z = file_time_tempname(g.argv[i], zSuffix);
1508 fossil_print("%s\n", z);
1509 fossil_free(z);
1510 }else{
1511 file_tempname(&x, g.argv[i]);
1512 fossil_print("%s\n", blob_str(&x));
1513 blob_reset(&x);
1514 }
1515 }
1516 }
1517
1518
1519 /*
1520
+61 -23
--- src/smtp.c
+++ src/smtp.c
@@ -1334,36 +1334,69 @@
13341334
z[0] = 0;
13351335
z++;
13361336
if( z[0]==0 || fossil_isspace(z[0]) ) return 0;
13371337
return z;
13381338
}
1339
+
1340
+/*
1341
+** Write formatted output back to the pop3 client, and also to the
1342
+** log file, if there is a log file.
1343
+*/
1344
+static void pop3_print(FILE *pLog, const char *zFormat, ...){
1345
+ va_list ap;
1346
+ char zLine[500];
1347
+ va_start(ap, zFormat);
1348
+ sqlite3_vsnprintf(sizeof(zLine),zLine,zFormat,ap);
1349
+ va_end(ap);
1350
+ printf("%s\r\n", zLine);
1351
+ fflush(stdout);
1352
+ if( pLog ) fprintf(pLog, "S: %s\n", zLine);
1353
+}
13391354
13401355
/*
13411356
** COMMAND: pop3d
13421357
**
13431358
** Usage: %fossil pop3d [OPTIONS] REPOSITORY
13441359
**
13451360
** Begin a POP3 conversation with a client using stdin/stdout using
13461361
** the mailboxes stored in REPOSITORY.
1362
+**
1363
+** If launched as root, the process first enters a chroot jail using
1364
+** the directory of REPOSITORY as root, then drops all privileges and
1365
+** assumes the user and group of REPOSITORY before reading any content
1366
+** off of the wire.
1367
+**
1368
+** --logdir DIR Each pop3d session creates a new logfile
1369
+** in the directory DIR and records a transcript
1370
+** of the session there. The logfile is opened
1371
+** before entering the chroot jail.
13471372
*/
13481373
void pop3d_command(void){
13491374
char *zDbName;
13501375
char *zA1, *zA2, *zCmd, *z;
13511376
int inAuth = 1;
13521377
int i;
1378
+ FILE *pLog;
1379
+ const char *zDir;
13531380
Stmt q;
13541381
char zIn[1000];
13551382
char zUser[100];
1383
+ zDir = find_option("logdir",0,1);
1384
+ if( zDir ){
1385
+ char *zFile = file_time_tempname(zDir, ".txt");
1386
+ pLog = fossil_fopen(zFile, "w");
1387
+ fossil_free(zFile);
1388
+ }
13561389
verify_all_options();
13571390
if( g.argc!=3 ) usage("DBNAME");
13581391
zDbName = g.argv[2];
13591392
zDbName = enter_chroot_jail(zDbName, 0);
13601393
db_open_repository(zDbName);
13611394
add_content_sql_commands(g.db);
1362
- printf("+OK POP3 server ready\r\n");
1363
- fflush(stdout);
1395
+ pop3_print(pLog, "+OK POP3 server ready");
13641396
while( fgets(zIn, sizeof(zIn), stdin) ){
1397
+ if( pLog ) fprintf(pLog, "C: %s", zIn);
13651398
zCmd = zIn;
13661399
zA1 = pop3d_arg(zCmd);
13671400
zA2 = zA1 ? pop3d_arg(zA1) : 0;
13681401
for(i=0; zCmd[i]; i++){ zCmd[i] = fossil_tolower(zCmd[i]); }
13691402
if( inAuth ){
@@ -1408,61 +1441,66 @@
14081441
break;
14091442
}
14101443
if( strcmp(zCmd,"stat")==0 ){
14111444
db_prepare(&q, "SELECT count(*), sum(esz) FROM pop3 WHERE NOT isDel");
14121445
if( db_step(&q)==SQLITE_ROW ){
1413
- printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
1446
+ pop3_print(pLog, "+OK %d %d",
1447
+ db_column_int(&q,0), db_column_int(&q,1));
14141448
}else{
1415
- printf("-ERR\r\n");
1449
+ pop3_print(pLog,"-ERR");
14161450
}
14171451
db_finalize(&q);
1418
- fflush(stdout);
14191452
continue;
14201453
}
14211454
if( strcmp(zCmd,"list")==0 ){
14221455
if( zA1 ){
14231456
db_prepare(&q, "SELECT id, esz FROM pop3"
14241457
" WHERE id=%d AND NOT isDel", atoi(zA1));
14251458
if( db_step(&q)==SQLITE_ROW ){
1426
- printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
1459
+ pop3_print(pLog, "+OK %d %d",
1460
+ db_column_int(&q,0), db_column_int(&q,1));
14271461
}else{
1428
- printf("-ERR\r\n");
1462
+ pop3_print(pLog, "-ERR");
14291463
}
14301464
}else{
1431
- printf("+OK\r\n");
1465
+ pop3_print(pLog, "+OK");
14321466
db_prepare(&q, "SELECT id, esz FROM pop3 WHERE NOT isDel");
14331467
while( db_step(&q)==SQLITE_ROW ){
1434
- printf("%d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
1468
+ pop3_print(pLog, "%d %d",
1469
+ db_column_int(&q,0), db_column_int(&q,1));
14351470
}
1436
- printf(".\r\n");
1471
+ pop3_print(pLog, ".");
14371472
}
1438
- fflush(stdout);
14391473
db_finalize(&q);
14401474
continue;
14411475
}
14421476
if( strcmp(zCmd,"retr")==0 ){
14431477
Blob all, line;
1478
+ int nLine = 0;
14441479
if( zA1==0 ) goto cmd_error;
14451480
z = db_text(0, "SELECT decompress(emailblob.etxt) "
14461481
" FROM emailblob, pop3"
14471482
" WHERE emailblob.emailid=pop3.emailid"
14481483
" AND pop3.id=%d AND NOT pop3.isDel",
14491484
atoi(zA1));
14501485
if( z==0 ) goto cmd_error;
1486
+ pop3_print(pLog, "+OK");
14511487
blob_init(&all, z, -1);
14521488
while( blob_line(&all, &line) ){
14531489
if( blob_buffer(&line)[0]=='.' ){
14541490
fputc('.', stdout);
14551491
}
14561492
fwrite(blob_buffer(&line), 1, blob_size(&line), stdout);
1493
+ nLine++;
14571494
}
1458
- printf(".\r\n");
1495
+ if( pLog ) fprintf(pLog, "S: # %d lines of content\n", nLine);
1496
+ pop3_print(pLog, ".");
14591497
fossil_free(z);
14601498
blob_reset(&all);
14611499
blob_reset(&line);
14621500
fflush(stdout);
1463
- goto cmd_ok;
1501
+ continue;
14641502
}
14651503
if( strcmp(zCmd,"dele")==0 ){
14661504
if( zA1==0 ) goto cmd_error;
14671505
db_multi_exec("UPDATE pop3 SET isDel=1 WHERE id=%d",atoi(zA1));
14681506
goto cmd_ok;
@@ -1477,36 +1515,36 @@
14771515
if( strcmp(zCmd,"uidl")==0 ){
14781516
if( zA1 ){
14791517
db_prepare(&q, "SELECT id, emailid FROM pop3"
14801518
" WHERE id=%d AND NOT isDel", atoi(zA1));
14811519
if( db_step(&q)==SQLITE_ROW ){
1482
- printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
1520
+ pop3_print(pLog, "+OK %d %d",
1521
+ db_column_int(&q,0), db_column_int(&q,1));
14831522
}else{
1484
- printf("-ERR\r\n");
1523
+ pop3_print(pLog,"-ERR");
14851524
}
14861525
}else{
1487
- printf("+OK\r\n");
1526
+ pop3_print(pLog, "+OK");
14881527
db_prepare(&q, "SELECT id, emailid FROM pop3 WHERE NOT isDel");
14891528
while( db_step(&q)==SQLITE_ROW ){
1490
- printf("%d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
1529
+ pop3_print(pLog, "%d %d",
1530
+ db_column_int(&q,0), db_column_int(&q,1));
14911531
}
1492
- printf(".\r\n");
1532
+ pop3_print(pLog, ".");
14931533
}
1494
- fflush(stdout);
14951534
db_finalize(&q);
14961535
continue;
14971536
}
14981537
if( strcmp(zCmd,"noop")==0 ){
14991538
goto cmd_ok;
15001539
}
15011540
/* Else, fall through into cmd_error */
15021541
}
15031542
cmd_error:
1504
- printf("-ERR\r\n");
1505
- fflush(stdout);
1543
+ pop3_print(pLog, "-ERR");
15061544
continue;
15071545
cmd_ok:
1508
- printf("+OK\r\n");
1509
- fflush(stdout);
1546
+ pop3_print(pLog, "+OK");
15101547
continue;
15111548
}
1549
+ if( pLog ) fclose(pLog);
15121550
}
15131551
--- src/smtp.c
+++ src/smtp.c
@@ -1334,36 +1334,69 @@
1334 z[0] = 0;
1335 z++;
1336 if( z[0]==0 || fossil_isspace(z[0]) ) return 0;
1337 return z;
1338 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1339
1340 /*
1341 ** COMMAND: pop3d
1342 **
1343 ** Usage: %fossil pop3d [OPTIONS] REPOSITORY
1344 **
1345 ** Begin a POP3 conversation with a client using stdin/stdout using
1346 ** the mailboxes stored in REPOSITORY.
 
 
 
 
 
 
 
 
 
 
1347 */
1348 void pop3d_command(void){
1349 char *zDbName;
1350 char *zA1, *zA2, *zCmd, *z;
1351 int inAuth = 1;
1352 int i;
 
 
1353 Stmt q;
1354 char zIn[1000];
1355 char zUser[100];
 
 
 
 
 
 
1356 verify_all_options();
1357 if( g.argc!=3 ) usage("DBNAME");
1358 zDbName = g.argv[2];
1359 zDbName = enter_chroot_jail(zDbName, 0);
1360 db_open_repository(zDbName);
1361 add_content_sql_commands(g.db);
1362 printf("+OK POP3 server ready\r\n");
1363 fflush(stdout);
1364 while( fgets(zIn, sizeof(zIn), stdin) ){
 
1365 zCmd = zIn;
1366 zA1 = pop3d_arg(zCmd);
1367 zA2 = zA1 ? pop3d_arg(zA1) : 0;
1368 for(i=0; zCmd[i]; i++){ zCmd[i] = fossil_tolower(zCmd[i]); }
1369 if( inAuth ){
@@ -1408,61 +1441,66 @@
1408 break;
1409 }
1410 if( strcmp(zCmd,"stat")==0 ){
1411 db_prepare(&q, "SELECT count(*), sum(esz) FROM pop3 WHERE NOT isDel");
1412 if( db_step(&q)==SQLITE_ROW ){
1413 printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
 
1414 }else{
1415 printf("-ERR\r\n");
1416 }
1417 db_finalize(&q);
1418 fflush(stdout);
1419 continue;
1420 }
1421 if( strcmp(zCmd,"list")==0 ){
1422 if( zA1 ){
1423 db_prepare(&q, "SELECT id, esz FROM pop3"
1424 " WHERE id=%d AND NOT isDel", atoi(zA1));
1425 if( db_step(&q)==SQLITE_ROW ){
1426 printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
 
1427 }else{
1428 printf("-ERR\r\n");
1429 }
1430 }else{
1431 printf("+OK\r\n");
1432 db_prepare(&q, "SELECT id, esz FROM pop3 WHERE NOT isDel");
1433 while( db_step(&q)==SQLITE_ROW ){
1434 printf("%d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
 
1435 }
1436 printf(".\r\n");
1437 }
1438 fflush(stdout);
1439 db_finalize(&q);
1440 continue;
1441 }
1442 if( strcmp(zCmd,"retr")==0 ){
1443 Blob all, line;
 
1444 if( zA1==0 ) goto cmd_error;
1445 z = db_text(0, "SELECT decompress(emailblob.etxt) "
1446 " FROM emailblob, pop3"
1447 " WHERE emailblob.emailid=pop3.emailid"
1448 " AND pop3.id=%d AND NOT pop3.isDel",
1449 atoi(zA1));
1450 if( z==0 ) goto cmd_error;
 
1451 blob_init(&all, z, -1);
1452 while( blob_line(&all, &line) ){
1453 if( blob_buffer(&line)[0]=='.' ){
1454 fputc('.', stdout);
1455 }
1456 fwrite(blob_buffer(&line), 1, blob_size(&line), stdout);
 
1457 }
1458 printf(".\r\n");
 
1459 fossil_free(z);
1460 blob_reset(&all);
1461 blob_reset(&line);
1462 fflush(stdout);
1463 goto cmd_ok;
1464 }
1465 if( strcmp(zCmd,"dele")==0 ){
1466 if( zA1==0 ) goto cmd_error;
1467 db_multi_exec("UPDATE pop3 SET isDel=1 WHERE id=%d",atoi(zA1));
1468 goto cmd_ok;
@@ -1477,36 +1515,36 @@
1477 if( strcmp(zCmd,"uidl")==0 ){
1478 if( zA1 ){
1479 db_prepare(&q, "SELECT id, emailid FROM pop3"
1480 " WHERE id=%d AND NOT isDel", atoi(zA1));
1481 if( db_step(&q)==SQLITE_ROW ){
1482 printf("+OK %d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
 
1483 }else{
1484 printf("-ERR\r\n");
1485 }
1486 }else{
1487 printf("+OK\r\n");
1488 db_prepare(&q, "SELECT id, emailid FROM pop3 WHERE NOT isDel");
1489 while( db_step(&q)==SQLITE_ROW ){
1490 printf("%d %d\r\n", db_column_int(&q,0), db_column_int(&q,1));
 
1491 }
1492 printf(".\r\n");
1493 }
1494 fflush(stdout);
1495 db_finalize(&q);
1496 continue;
1497 }
1498 if( strcmp(zCmd,"noop")==0 ){
1499 goto cmd_ok;
1500 }
1501 /* Else, fall through into cmd_error */
1502 }
1503 cmd_error:
1504 printf("-ERR\r\n");
1505 fflush(stdout);
1506 continue;
1507 cmd_ok:
1508 printf("+OK\r\n");
1509 fflush(stdout);
1510 continue;
1511 }
 
1512 }
1513
--- src/smtp.c
+++ src/smtp.c
@@ -1334,36 +1334,69 @@
1334 z[0] = 0;
1335 z++;
1336 if( z[0]==0 || fossil_isspace(z[0]) ) return 0;
1337 return z;
1338 }
1339
1340 /*
1341 ** Write formatted output back to the pop3 client, and also to the
1342 ** log file, if there is a log file.
1343 */
1344 static void pop3_print(FILE *pLog, const char *zFormat, ...){
1345 va_list ap;
1346 char zLine[500];
1347 va_start(ap, zFormat);
1348 sqlite3_vsnprintf(sizeof(zLine),zLine,zFormat,ap);
1349 va_end(ap);
1350 printf("%s\r\n", zLine);
1351 fflush(stdout);
1352 if( pLog ) fprintf(pLog, "S: %s\n", zLine);
1353 }
1354
1355 /*
1356 ** COMMAND: pop3d
1357 **
1358 ** Usage: %fossil pop3d [OPTIONS] REPOSITORY
1359 **
1360 ** Begin a POP3 conversation with a client using stdin/stdout using
1361 ** the mailboxes stored in REPOSITORY.
1362 **
1363 ** If launched as root, the process first enters a chroot jail using
1364 ** the directory of REPOSITORY as root, then drops all privileges and
1365 ** assumes the user and group of REPOSITORY before reading any content
1366 ** off of the wire.
1367 **
1368 ** --logdir DIR Each pop3d session creates a new logfile
1369 ** in the directory DIR and records a transcript
1370 ** of the session there. The logfile is opened
1371 ** before entering the chroot jail.
1372 */
1373 void pop3d_command(void){
1374 char *zDbName;
1375 char *zA1, *zA2, *zCmd, *z;
1376 int inAuth = 1;
1377 int i;
1378 FILE *pLog;
1379 const char *zDir;
1380 Stmt q;
1381 char zIn[1000];
1382 char zUser[100];
1383 zDir = find_option("logdir",0,1);
1384 if( zDir ){
1385 char *zFile = file_time_tempname(zDir, ".txt");
1386 pLog = fossil_fopen(zFile, "w");
1387 fossil_free(zFile);
1388 }
1389 verify_all_options();
1390 if( g.argc!=3 ) usage("DBNAME");
1391 zDbName = g.argv[2];
1392 zDbName = enter_chroot_jail(zDbName, 0);
1393 db_open_repository(zDbName);
1394 add_content_sql_commands(g.db);
1395 pop3_print(pLog, "+OK POP3 server ready");
 
1396 while( fgets(zIn, sizeof(zIn), stdin) ){
1397 if( pLog ) fprintf(pLog, "C: %s", zIn);
1398 zCmd = zIn;
1399 zA1 = pop3d_arg(zCmd);
1400 zA2 = zA1 ? pop3d_arg(zA1) : 0;
1401 for(i=0; zCmd[i]; i++){ zCmd[i] = fossil_tolower(zCmd[i]); }
1402 if( inAuth ){
@@ -1408,61 +1441,66 @@
1441 break;
1442 }
1443 if( strcmp(zCmd,"stat")==0 ){
1444 db_prepare(&q, "SELECT count(*), sum(esz) FROM pop3 WHERE NOT isDel");
1445 if( db_step(&q)==SQLITE_ROW ){
1446 pop3_print(pLog, "+OK %d %d",
1447 db_column_int(&q,0), db_column_int(&q,1));
1448 }else{
1449 pop3_print(pLog,"-ERR");
1450 }
1451 db_finalize(&q);
 
1452 continue;
1453 }
1454 if( strcmp(zCmd,"list")==0 ){
1455 if( zA1 ){
1456 db_prepare(&q, "SELECT id, esz FROM pop3"
1457 " WHERE id=%d AND NOT isDel", atoi(zA1));
1458 if( db_step(&q)==SQLITE_ROW ){
1459 pop3_print(pLog, "+OK %d %d",
1460 db_column_int(&q,0), db_column_int(&q,1));
1461 }else{
1462 pop3_print(pLog, "-ERR");
1463 }
1464 }else{
1465 pop3_print(pLog, "+OK");
1466 db_prepare(&q, "SELECT id, esz FROM pop3 WHERE NOT isDel");
1467 while( db_step(&q)==SQLITE_ROW ){
1468 pop3_print(pLog, "%d %d",
1469 db_column_int(&q,0), db_column_int(&q,1));
1470 }
1471 pop3_print(pLog, ".");
1472 }
 
1473 db_finalize(&q);
1474 continue;
1475 }
1476 if( strcmp(zCmd,"retr")==0 ){
1477 Blob all, line;
1478 int nLine = 0;
1479 if( zA1==0 ) goto cmd_error;
1480 z = db_text(0, "SELECT decompress(emailblob.etxt) "
1481 " FROM emailblob, pop3"
1482 " WHERE emailblob.emailid=pop3.emailid"
1483 " AND pop3.id=%d AND NOT pop3.isDel",
1484 atoi(zA1));
1485 if( z==0 ) goto cmd_error;
1486 pop3_print(pLog, "+OK");
1487 blob_init(&all, z, -1);
1488 while( blob_line(&all, &line) ){
1489 if( blob_buffer(&line)[0]=='.' ){
1490 fputc('.', stdout);
1491 }
1492 fwrite(blob_buffer(&line), 1, blob_size(&line), stdout);
1493 nLine++;
1494 }
1495 if( pLog ) fprintf(pLog, "S: # %d lines of content\n", nLine);
1496 pop3_print(pLog, ".");
1497 fossil_free(z);
1498 blob_reset(&all);
1499 blob_reset(&line);
1500 fflush(stdout);
1501 continue;
1502 }
1503 if( strcmp(zCmd,"dele")==0 ){
1504 if( zA1==0 ) goto cmd_error;
1505 db_multi_exec("UPDATE pop3 SET isDel=1 WHERE id=%d",atoi(zA1));
1506 goto cmd_ok;
@@ -1477,36 +1515,36 @@
1515 if( strcmp(zCmd,"uidl")==0 ){
1516 if( zA1 ){
1517 db_prepare(&q, "SELECT id, emailid FROM pop3"
1518 " WHERE id=%d AND NOT isDel", atoi(zA1));
1519 if( db_step(&q)==SQLITE_ROW ){
1520 pop3_print(pLog, "+OK %d %d",
1521 db_column_int(&q,0), db_column_int(&q,1));
1522 }else{
1523 pop3_print(pLog,"-ERR");
1524 }
1525 }else{
1526 pop3_print(pLog, "+OK");
1527 db_prepare(&q, "SELECT id, emailid FROM pop3 WHERE NOT isDel");
1528 while( db_step(&q)==SQLITE_ROW ){
1529 pop3_print(pLog, "%d %d",
1530 db_column_int(&q,0), db_column_int(&q,1));
1531 }
1532 pop3_print(pLog, ".");
1533 }
 
1534 db_finalize(&q);
1535 continue;
1536 }
1537 if( strcmp(zCmd,"noop")==0 ){
1538 goto cmd_ok;
1539 }
1540 /* Else, fall through into cmd_error */
1541 }
1542 cmd_error:
1543 pop3_print(pLog, "-ERR");
 
1544 continue;
1545 cmd_ok:
1546 pop3_print(pLog, "+OK");
 
1547 continue;
1548 }
1549 if( pLog ) fclose(pLog);
1550 }
1551

Keyboard Shortcuts

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