Fossil SCM
Initial implementation of the "fossil pop3d" command.
Commit
bf13815cd5483d6dcf05dcf65def859dd089494656cfacd90761444eb37df441
Parent
34b9502698d25a5…
1 file changed
+191
+191
| --- src/smtp.c | ||
| +++ src/smtp.c | ||
| @@ -1317,5 +1317,196 @@ | ||
| 1317 | 1317 | smtp_server_send(&x, "500 unknown command\r\n"); |
| 1318 | 1318 | } |
| 1319 | 1319 | } |
| 1320 | 1320 | smtp_server_clear(&x, SMTPSRV_CLEAR_ALL); |
| 1321 | 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 | +} | |
| 1322 | 1513 |
| --- 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 |