Index: trunk/ippTools/share/pubtool_definerun.sql
===================================================================
--- trunk/ippTools/share/pubtool_definerun.sql	(revision 28387)
+++ trunk/ippTools/share/pubtool_definerun.sql	(revision 28411)
@@ -38,4 +38,24 @@
         AND (camRun.magicked != 0 OR publishClient.magicked = 0)
     -- WHERE hook %s
+    UNION
+    -- Get diffphots to publish
+    SELECT DISTINCT
+        client_id,
+        diff_phot_id AS stage_id,
+        diffPhotRun.label AS src_label
+    FROM publishClient
+    JOIN diffPhotRun
+    JOIN diffRun USING(diff_id)
+    JOIN diffInputSkyfile USING(diff_id)
+    JOIN warpRun ON warpRun.warp_id = diffInputSkyfile.warp1 -- Only JOINing input, not reference!
+    JOIN fakeRun USING(fake_id)
+    JOIN camRun USING(cam_id)
+    JOIN chipRun USING(chip_id)
+    JOIN rawExp USING(exp_id)
+    WHERE publishClient.stage = 'diffphot'
+        AND publishClient.active = 1
+        AND diffPhotRun.state IN ('full', 'cleaned', 'goto_cleaned')
+        AND (diffRun.diff_mode = 4 OR publishClient.magicked = 0) -- diffPhotRun doesn't respect magic
+    -- WHERE hook %s
     ) AS publishToDo
 -- Only get stuff that hasn't been published
Index: trunk/ippTools/share/pubtool_pending.sql
===================================================================
--- trunk/ippTools/share/pubtool_pending.sql	(revision 28387)
+++ trunk/ippTools/share/pubtool_pending.sql	(revision 28411)
@@ -50,4 +50,30 @@
         AND (camRun.magicked != 0 OR publishClient.magicked = 0)
         -- WHERE hook %s
+    SELECT DISTINCT
+        publishRun.pub_id,
+        publishClient.product,
+        publishClient.stage,
+        publishClient.workdir,
+        diffPhotRun.diff_phot_id AS stage_id,
+        rawExp.camera,
+        rawExp.exp_id
+    FROM publishRun
+    JOIN publishClient USING(client_id)
+    JOIN diffPhotRun
+        ON diffPhotRun.diff_phot_id = publishRun.stage_id
+    JOIN diffRun USING(diff_id)
+    JOIN diffInputSkyfile USING(diff_id)
+    -- Need to do something fancy here to get the camera name for a stack
+    LEFT JOIN warpRun ON warpRun.warp_id = diffInputSkyfile.warp1
+    JOIN fakeRun USING(fake_id)
+    JOIN camRun USING(cam_id)
+    JOIN chipRun USING(chip_id)
+    JOIN rawExp USING(exp_id)
+    WHERE publishClient.stage = 'diffphot'
+        AND publishClient.active = 1
+        AND publishRun.state = 'new'
+        AND diffPhotRun.state IN ('full', 'cleaned', 'goto_cleaned')
+        AND (diffRun.diff_mode = 4 OR publishClient.magicked = 0) -- diffPhotRun doesn't respect magic
+        -- WHERE hook %s
 ) AS publishToDo
 LEFT JOIN publishDone USING(pub_id)
Index: trunk/ippTools/src/pubtool.c
===================================================================
--- trunk/ippTools/src/pubtool.c	(revision 28387)
+++ trunk/ippTools/src/pubtool.c	(revision 28411)
@@ -153,4 +153,5 @@
     psMetadata *diffWhere = psMetadataAlloc(); // WHERE conditions for diffs
     psMetadata *camWhere = psMetadataAlloc(); // WHERE conditions for cams
+    psMetadata *diffphotWhere = psMetadataAlloc(); // WHERE conditions for diffphots
 
     // required
@@ -173,4 +174,12 @@
     PXOPT_COPY_STR(config->args, camWhere, "-obs_mode", "rawExp.obs_mode", "LIKE");
 
+    PXOPT_COPY_S64(config->args, diffphotWhere, "-client_id", "client_id", "==");
+    pxAddLabelSearchArgs(config, diffphotWhere, "-label", "diffphotRun.label", "==");
+    pxAddLabelSearchArgs(config, diffphotWhere, "-data_group", "diffphotRun.data_group", "LIKE");
+    PXOPT_COPY_TIME(config->args, diffphotWhere, "-dateobs_begin", "rawExp.dateobs", ">=");
+    PXOPT_COPY_TIME(config->args, diffphotWhere, "-dateobs_end", "rawExp.dateobs", "<=");
+    PXOPT_COPY_STR(config->args, diffphotWhere, "-filter", "rawExp.filter", "LIKE");
+    PXOPT_COPY_STR(config->args, diffphotWhere, "-obs_mode", "rawExp.obs_mode", "LIKE");
+
     PXOPT_LOOKUP_STR(set_label, config->args, "-set_label", false, false);
     PXOPT_LOOKUP_BOOL(rerun, config->args, "-rerun", false);
@@ -201,4 +210,5 @@
         psFree(diffWhere);
         psFree(camWhere);
+        psFree(diffphotWhere);
         return false;
     }
@@ -220,9 +230,18 @@
     psFree(camWhere);
 
-    if (!p_psDBRunQueryF(config->dbh, query, whereDiff, whereCam)) {
+    psString whereDiffphot = psStringCopy(""); // Additional constraints to add to query
+    if (psListLength(diffphotWhere->list)) {
+        psString clause = psDBGenerateWhereConditionSQL(diffphotWhere, NULL);
+        psStringAppend(&whereDiffphot, "\n AND %s", clause);
+        psFree(clause);
+    }
+    psFree(diffphotWhere);
+
+    if (!p_psDBRunQueryF(config->dbh, query, whereDiff, whereCam, whereDiffphot)) {
         psError(PS_ERR_UNKNOWN, false, "Database error");
         psFree(query);
         psFree(whereDiff);
         psFree(whereCam);
+        psFree(whereDiffphot);
         if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "Database error");
@@ -233,4 +252,5 @@
     psFree(whereDiff);
     psFree(whereCam);
+    psFree(whereDiffphot);
 
     psArray *output = p_psDBFetchResult(config->dbh); // Output of SELECT statement
