Fossil SCM

Initial implementation of the "fossil pop3d" command.

drh 2018-07-17 23:50 trunk
Commit bf13815cd5483d6dcf05dcf65def859dd089494656cfacd90761444eb37df441
1 file changed +191
+191
--- src/smtp.c
+++ src/smtp.c
@@ -1317,5 +1317,196 @@
13171317
smtp_server_send(&x, "500 unknown command\r\n");
13181318
}
13191319
}
13201320
smtp_server_clear(&x, SMTPSRV_CLEAR_ALL);
13211321
}
1322
+
1323
+/*
1324
+** Zero-terminate the argument. Return a pointer the start of the
1325
+** next argument, or to NULL if there are no more arguments.
1326
+*/
1327
+static char *pop3d_arg(char *z){
1328
+ if( z[0]==0 || fossil_isspace(z[0]) ){
1329
+ return 0;
1330
+ }
1331
+ z++;
1332
+ while( z[0] && !fossil_isspace(z[0]) ){ z++; }
1333
+ if( z[0]==0 ) return 0;
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 ){
1370
+ if( strcmp(zCmd,"user")==0 ){
1371
+ if( zA1==0 || zA2!=0 ) goto cmd_error;
1372
+ sqlite3_snprintf(sizeof(zUser),zUser,"%s",zA1);
1373
+ goto cmd_ok;
1374
+ }
1375
+ if( strcmp(zCmd,"pass")==0 ){
1376
+ if( zA1==0 || zA2!=0 ) goto cmd_error;
1377
+ if( login_search_uid(zUser,zA1)==0 ){
1378
+ goto cmd_error;
1379
+ }else{
1380
+ inAuth = 0;
1381
+ db_multi_exec(
1382
+ "CREATE TEMP TABLE pop3("
1383
+ " id INTEGER PRIMARY KEY,"
1384
+ " emailid INT,"
1385
+ " ebid INT,"
1386
+ " isDel INT,"
1387
+ " esz INT"
1388
+ ");"
1389
+ "INSERT INTO pop3(id,emailid,ebid,isDel,esz)"
1390
+ " SELECT NULL, emailid, ebid, 0, esz FROM emailblob, emailbox"
1391
+ " WHERE emailid=emsgid AND euser=%Q AND estate<=1"
1392
+ " ORDER BY edate;",
1393
+ zUser
1394
+ );
1395
+ goto cmd_ok;
1396
+ }
1397
+ }
1398
+ if( strcmp(zCmd,"quit")==0 ) break;
1399
+ /* Fossil cannot process APOP since the users clear-text password is
1400
+ ** unknown. */
1401
+ goto cmd_error;
1402
+ }else{
1403
+ if( strcmp(zCmd,"quit")==0 ){
1404
+ db_multi_exec(
1405
+ "UPDATE emailbox SET estate=2"
1406
+ " WHERE estate<2 AND ebid IN (SELECT ebid FROM pop3 WHERE isDel);"
1407
+ );
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;
1469
+ }
1470
+ if( strcmp(zCmd,"rset")==0 ){
1471
+ db_multi_exec("UPDATE pop3 SET isDel=0");
1472
+ goto cmd_ok;
1473
+ }
1474
+ if( strcmp(zCmd,"top")==0 ){
1475
+ goto cmd_error;
1476
+ }
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
+}
13221513
--- src/smtp.c
+++ src/smtp.c
@@ -1317,5 +1317,196 @@
1317 smtp_server_send(&x, "500 unknown command\r\n");
1318 }
1319 }
1320 smtp_server_clear(&x, SMTPSRV_CLEAR_ALL);
1321 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1322
--- src/smtp.c
+++ src/smtp.c
@@ -1317,5 +1317,196 @@
1317 smtp_server_send(&x, "500 unknown command\r\n");
1318 }
1319 }
1320 smtp_server_clear(&x, SMTPSRV_CLEAR_ALL);
1321 }
1322
1323 /*
1324 ** Zero-terminate the argument. Return a pointer the start of the
1325 ** next argument, or to NULL if there are no more arguments.
1326 */
1327 static char *pop3d_arg(char *z){
1328 if( z[0]==0 || fossil_isspace(z[0]) ){
1329 return 0;
1330 }
1331 z++;
1332 while( z[0] && !fossil_isspace(z[0]) ){ z++; }
1333 if( z[0]==0 ) return 0;
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 ){
1370 if( strcmp(zCmd,"user")==0 ){
1371 if( zA1==0 || zA2!=0 ) goto cmd_error;
1372 sqlite3_snprintf(sizeof(zUser),zUser,"%s",zA1);
1373 goto cmd_ok;
1374 }
1375 if( strcmp(zCmd,"pass")==0 ){
1376 if( zA1==0 || zA2!=0 ) goto cmd_error;
1377 if( login_search_uid(zUser,zA1)==0 ){
1378 goto cmd_error;
1379 }else{
1380 inAuth = 0;
1381 db_multi_exec(
1382 "CREATE TEMP TABLE pop3("
1383 " id INTEGER PRIMARY KEY,"
1384 " emailid INT,"
1385 " ebid INT,"
1386 " isDel INT,"
1387 " esz INT"
1388 ");"
1389 "INSERT INTO pop3(id,emailid,ebid,isDel,esz)"
1390 " SELECT NULL, emailid, ebid, 0, esz FROM emailblob, emailbox"
1391 " WHERE emailid=emsgid AND euser=%Q AND estate<=1"
1392 " ORDER BY edate;",
1393 zUser
1394 );
1395 goto cmd_ok;
1396 }
1397 }
1398 if( strcmp(zCmd,"quit")==0 ) break;
1399 /* Fossil cannot process APOP since the users clear-text password is
1400 ** unknown. */
1401 goto cmd_error;
1402 }else{
1403 if( strcmp(zCmd,"quit")==0 ){
1404 db_multi_exec(
1405 "UPDATE emailbox SET estate=2"
1406 " WHERE estate<2 AND ebid IN (SELECT ebid FROM pop3 WHERE isDel);"
1407 );
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;
1469 }
1470 if( strcmp(zCmd,"rset")==0 ){
1471 db_multi_exec("UPDATE pop3 SET isDel=0");
1472 goto cmd_ok;
1473 }
1474 if( strcmp(zCmd,"top")==0 ){
1475 goto cmd_error;
1476 }
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

Keyboard Shortcuts

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