Index: trunk/ippTools/src/pstamptool.c
===================================================================
--- trunk/ippTools/src/pstamptool.c	(revision 16134)
+++ trunk/ippTools/src/pstamptool.c	(revision 16277)
@@ -36,14 +36,8 @@
 static bool pendingReqMode(pxConfig *config);
 static bool processedReqMode(pxConfig *config);
-#ifdef notyet
 static bool addJobMode(pxConfig *config);
+static bool listJobMode(pxConfig *config);
 static bool pendingJobMode(pxConfig *config);
-
-static bool copydoneMode(pxConfig *config);
-
-static bool copydoneCompleteExp(pxConfig *config);
-static psArray *pzGetPendingCameras(pxConfig *config);
-static psArray *pzArrayZip(psArray *arraySet, psS64 limit);
-#endif // notyet
+static bool processedJobMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -71,4 +65,8 @@
         MODECASE(PSTAMPTOOL_MODE_PENDINGREQ, pendingReqMode);
         MODECASE(PSTAMPTOOL_MODE_PROCESSEDREQ, processedReqMode);
+        MODECASE(PSTAMPTOOL_MODE_ADDJOB, addJobMode);
+        MODECASE(PSTAMPTOOL_MODE_LISTJOB, listJobMode);
+        MODECASE(PSTAMPTOOL_MODE_PENDINGJOB, pendingJobMode);
+        MODECASE(PSTAMPTOOL_MODE_PROCESSEDJOB, processedJobMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -206,5 +204,5 @@
     }
 
-    char *query ="INSERT INTO psRequest"
+    char *query ="INSERT INTO pstampRequest"
                  " (state, uri)"
                  " VALUES( 'new', '%s')";
@@ -224,4 +222,7 @@
     }
 
+    psS64 req_id = psDBLastInsertID(config->dbh);
+    printf("%ld\n", req_id);
+
     return true;
 }
@@ -241,10 +242,10 @@
             "SELECT"
             " *"
-            " FROM psRequest"
+            " FROM pstampRequest"
             " WHERE state = 'new'"
         );
 
     if (config->where) {
-        psString whereClause = psDBGenerateWhereConditionSQL(config->where, "psRequest");
+        psString whereClause = psDBGenerateWhereConditionSQL(config->where, "pstampRequest");
         psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
@@ -288,5 +289,5 @@
 
     // negative simple so the default is true
-    if (!ippdbPrintMetadatas(stdout, output, "pzPendingExp", !simple)) {
+    if (!ippdbPrintMetadatas(stdout, output, "pstampRequest", !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print array");
         psFree(output);
@@ -298,4 +299,5 @@
     return true;
 }
+
 static bool processedReqMode(pxConfig *config)
 {
@@ -325,5 +327,5 @@
     // XXX: check state for a legal value
 
-    char *query ="UPDATE psRequest"
+    char *query ="UPDATE pstampRequest"
                  " SET state = '%s'"
                  " WHERE req_id = '%s'";
@@ -337,9 +339,294 @@
     psU64 affected = psDBAffectedRows(config->dbh);
     if (affected != 1) {
-        psError(PS_ERR_UNKNOWN, false, "should have affected one row but %" PRIu64 " rows were modified",
+        psError(PS_ERR_UNKNOWN, false, "should have affected one row but %" 
+                                        PRIu64 " rows were modified", affected);
+        return false;
+    }
+
+    return true;
+}
+static bool addJobMode(pxConfig *config)
+{
+    bool    status;
+
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psString uri = psMetadataLookupStr(&status, config->args, "-uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -uri");
+        return false;
+    }
+    if (!uri) {
+        psError(PS_ERR_UNKNOWN, true, "-uri is required");
+        return false;
+    }
+
+    psString req_id = psMetadataLookupStr(&status, config->args, "-req_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -req_id");
+        return false;
+    }
+    if (!req_id) {
+        psError(PS_ERR_UNKNOWN, true, "-req_id is required");
+        return false;
+    }
+
+    psString outputBase = psMetadataLookupStr(&status, config->args, "-outputBase");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -outputBase");
+        return false;
+    }
+    if (!outputBase) {
+        psError(PS_ERR_UNKNOWN, true, "-outputBase is required");
+        return false;
+    }
+
+    psString argString = psMetadataLookupStr(&status, config->args, "-args");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -args");
+        return false;
+    }
+    if (!argString) {
+        psError(PS_ERR_UNKNOWN, true, "-args is required");
+        return false;
+    }
+
+    char *query ="INSERT INTO pstampJob"
+                 " (req_id, state, uri, outputBase, args)"
+                 " VALUES( %s, 'new', '%s', '%s', '%s')";
+
+    if (!p_psDBRunQuery(config->dbh, query, req_id, uri, outputBase, argString)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    psU64 affected = psDBAffectedRows(config->dbh);
+    if (affected != 1) {
+        psError(PS_ERR_UNKNOWN, false, 
+            "should have affected one row but %" PRIu64 " rows were modified",
             affected);
         return false;
     }
 
-    return true;
-}
+    psS64 job_id = psDBLastInsertID(config->dbh);
+    printf("%ld\n", job_id);
+
+    return true;
+}
+
+static bool listJobMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool status = false;
+    psU64 limit = psMetadataLookupU64(&status, config->args, "-limit");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -limit");
+        return false;
+    }
+
+    psString query = NULL;
+
+    psString req_id = psMetadataLookupStr(&status, config->args, "-req_id");
+    psString job_id = psMetadataLookupStr(&status, config->args, "-job_id");
+    
+    if (req_id) {
+        psStringAppend(&query,
+                "SELECT"
+                " *"
+                " FROM pstampJob"
+                " WHERE req_id = %s", req_id
+            );
+    } else if (job_id) {
+        psStringAppend(&query,
+                "SELECT"
+                " *"
+                " FROM pstampJob"
+                " WHERE job_id = %s", job_id
+            );
+    } else {
+        fprintf(stderr, "either req_id or job_id must be specified\n");
+        exit (1);
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("pstamptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    bool simple = false;
+    {
+        bool status = false;
+        simple = psMetadataLookupBool(&status, config->args, "-simple");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
+            psFree(output);
+            return false;
+        }
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "pstampJob", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+static bool pendingJobMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    bool status = false;
+    psU64 limit = psMetadataLookupU64(&status, config->args, "-limit");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -limit");
+        return false;
+    }
+
+    psString query = psStringCopy(
+            "SELECT"
+            " *"
+            " FROM pstampJob"
+            " WHERE state = 'new'"
+        );
+
+    if (config->where) {
+        psString whereClause = psDBGenerateWhereConditionSQL(config->where, "pstampJob");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("pstamptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    bool simple = false;
+    {
+        bool status = false;
+        simple = psMetadataLookupBool(&status, config->args, "-simple");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
+            psFree(output);
+            return false;
+        }
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "pstampJob", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+static bool processedJobMode(pxConfig *config)
+{
+    bool    status;
+
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psString job_id = psMetadataLookupStr(&status, config->args, "-job_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -job_id");
+        return false;
+    }
+    if (!job_id) {
+        psError(PS_ERR_UNKNOWN, true, "-job_id is required");
+        return false;
+    }
+    psString state = psMetadataLookupStr(&status, config->args, "-state");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -state");
+        return false;
+    }
+    if (!state) {
+        psError(PS_ERR_UNKNOWN, true, "-state is required");
+        return false;
+    }
+    psString jobStatus = psMetadataLookupStr(&status, config->args, "-status");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -status");
+        return false;
+    }
+
+    psString statusStr = NULL;
+    if (!jobStatus) {
+        statusStr = psStringCopy("");
+    } else {
+        psStringAppend(&statusStr, ", status = '%s'", jobStatus);
+    }
+        
+
+    // XXX: check state for a legal value
+
+    char *query ="UPDATE pstampJob"
+                 " SET state = '%s' %s"
+                 " WHERE job_id = '%s'";
+
+    if (!p_psDBRunQuery(config->dbh, query, state, statusStr, job_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(statusStr);
+
+    psU64 affected = psDBAffectedRows(config->dbh);
+    if (affected != 1) {
+        psError(PS_ERR_UNKNOWN, false, "should have affected one row but %" 
+                                        PRIu64 " rows were modified", affected);
+        return false;
+    }
+
+    return true;
+}
