Index: branches/eam_branches/ippTools.20200226/share/stacktool_addexternal.sql
===================================================================
--- branches/eam_branches/ippTools.20200226/share/stacktool_addexternal.sql	(revision 41294)
+++ branches/eam_branches/ippTools.20200226/share/stacktool_addexternal.sql	(revision 41294)
@@ -0,0 +1,3 @@
+
+INSERT into stackExtCamera
+ (ext_camera_id, ext_camera_name) = (0, '@EXT_CAMERA@')
Index: branches/eam_branches/ippTools.20200226/src/stacktool.c
===================================================================
--- branches/eam_branches/ippTools.20200226/src/stacktool.c	(revision 41293)
+++ branches/eam_branches/ippTools.20200226/src/stacktool.c	(revision 41294)
@@ -53,4 +53,6 @@
 static bool exportrunMode(pxConfig *config);
 static bool importrunMode(pxConfig *config);
+static bool importexternalMode(pxConfig *config);
+static bool addexternalMode(pxConfig *config);
 
 static bool setstackRunState(pxConfig *config, psS64 stack_id, const char *state);
@@ -96,4 +98,6 @@
         MODECASE(STACKTOOL_MODE_EXPORTRUN,             exportrunMode);
         MODECASE(STACKTOOL_MODE_IMPORTRUN,             importrunMode);
+        MODECASE(STACKTOOL_MODE_IMPORTEXTERNAL,        importexternalMode);
+        MODECASE(STACKTOOL_MODE_ADDEXTERNAL,           addexternalMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -2138,2 +2142,124 @@
   return true;
 }
+
+// in this mode, the supplied stacks are inserted into the db and the
+// StackExternalStack table is updated with the IDs of the inserted stack
+bool importexternalMode(pxConfig *config)
+{
+    unsigned int nFail;
+
+    int numImportTables = 2;
+
+    char tables[2] [80] = {"stackInputSkyfile", "stackSumSkyfile"};
+
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
+
+    psMetadata *input = psMetadataConfigRead (NULL, &nFail, infile, false);
+
+#ifdef notdef
+    fprintf (stderr, "---- input ----\n");
+    psMetadataPrint (stderr, input, 1);
+#endif
+
+    // XXX do we need to do this?
+    if (!pxCheckImportVersion(config, input)) {
+	psError(PS_ERR_UNKNOWN, false, "pxCheckImportVersion failed");
+	return false;
+    }
+    psMetadataItem *item = psMetadataLookup (input, "stackRun");
+    psAssert (item, "entry not in input?");
+    psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+    psMetadataItem *entry = psListGet (item->data.list, 0);
+    assert (entry);
+    assert (entry->type == PS_DATA_METADATA);
+    stackRunRow *stackRun = stackRunObjectFromMetadata (entry->data.md);
+
+    // save the original stack_id and insert with stack_id = 0 to force a
+    // new iD.  we then need to retrieve that ID and use it below
+    // the new stackRun should 
+
+    psS64 ext_stack_id = stackRun->stack_id;
+    stackRun->stack_id = 0;
+
+    // update filter as well..
+    // stackRun->filter = new_filter;
+
+    if (!psDBTransaction(config->dbh)) {
+	psError(PS_ERR_UNKNOWN, false, "database error");
+	psFree(where);
+	return false;
+    }
+
+    stackRunInsertObject (config->dbh, stackRun);
+
+    // get the new stack_id
+    psS64 stack_id = psDBLastInsertID(config->dbh);
+
+    if (!psDBCommit(config->dbh)) {
+	psError(PS_ERR_UNKNOWN, false, "database error");
+	psFree(list);
+	return false;
+    }
+
+    psMetadataItem *item = psMetadataLookup (input, "stackSumSkyfile");
+
+    psAssert (item, "entry not in input?");
+    psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+    for (int i = 0; i < item->data.list->n; i++) {
+	entry = psListGet (item->data.list, i);
+	assert (entry);
+	assert (entry->type == PS_DATA_METADATA);
+	stackSumSkyfileRow *stackSumSkyfile = stackSumSkyfileObjectFromMetadata (entry->data.md);
+
+	// need to update stack_id
+	stackSumSkyfile->stack_id = stack_id;
+	stackSumSkyfileInsertObject (config->dbh, stackSumSkyfile);
+
+	// fprintf (stdout, "---- row %d ----\n", i);
+	// psMetadataPrint (stderr, entry->data.md, 1);
+    }
+
+    return true;
+}
+
+bool addexternalMode(pxConfig *config) {
+
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_STR(ext_camera, config->args, "-ext_camera", true,  false);
+
+    psString query = pxDataGet("stacktool_addexternal.sql");
+    if (!query) {
+	psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+	return false;
+    }
+
+    psStringSubstitute(&query, ext_camera, "@EXT_CAMERA@");
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(where);
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+	psError(PS_ERR_UNKNOWN,false, "database error");
+	psFree(select);
+	return(NULL);
+    }
+
+    int ext_camera_id = psDBLastInsertID(config->dbh);
+    psLogMsg("stacktool", PS_LOG_INFO, "Added new external camera %s (ID = %d)", ext_camera, ext_camera_id);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(list);
+        return false;
+    }
+
+    return true;
+}
Index: branches/eam_branches/ippTools.20200226/src/stacktool.h
===================================================================
--- branches/eam_branches/ippTools.20200226/src/stacktool.h	(revision 41293)
+++ branches/eam_branches/ippTools.20200226/src/stacktool.h	(revision 41294)
@@ -46,5 +46,7 @@
     STACKTOOL_MODE_UPDATESUMSKYFILE,
     STACKTOOL_MODE_EXPORTRUN,
-    STACKTOOL_MODE_IMPORTRUN
+    STACKTOOL_MODE_IMPORTRUN,
+    STACKTOOL_MODE_IMPORTEXTERNAL,
+    STACKTOOL_MODE_ADDEXTERNAL
 } stacktoolMode;
 
Index: branches/eam_branches/ippTools.20200226/src/stacktoolConfig.c
===================================================================
--- branches/eam_branches/ippTools.20200226/src/stacktoolConfig.c	(revision 41293)
+++ branches/eam_branches/ippTools.20200226/src/stacktoolConfig.c	(revision 41294)
@@ -335,4 +335,12 @@
     psMetadataAddStr(importrunArgs, PS_LIST_TAIL, "-infile",  0,          "import from this file (required)", NULL);
 
+    // -importexternal
+    psMetadata *importexternalArgs = psMetadataAlloc();
+    psMetadataAddStr(importexternalArgs, PS_LIST_TAIL, "-infile",  0,          "import from this file (required)", NULL);
+    psMetadataAddStr(importexternalArgs, PS_LIST_TAIL, "-ext_camera",  0,      "external stacks come from this camera (required)", NULL);
+
+    // -addexternalcamera
+    psMetadata *addexternalArgs = psMetadataAlloc();
+    psMetadataAddStr(addexternalArgs, PS_LIST_TAIL, "-ext_camera",  0,      "external camera which can supply stacks (required)", NULL);
 
     psFree(now);
@@ -368,4 +376,7 @@
     PXOPT_ADD_MODE("-importrun",            "import run from metadata file",           STACKTOOL_MODE_IMPORTRUN, importrunArgs);
 
+    PXOPT_ADD_MODE("-importexternal",       "import stacks from external camera from metadata file", STACKTOOL_MODE_IMPORTEXTERNAL, importexternalArgs);
+    PXOPT_ADD_MODE("-addexternal",          "add external camera which can supply stacks", STACKTOOL_MODE_ADDEXTERNAL, addexternalArgs);
+
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
         psError(PS_ERR_UNKNOWN, true, "option parsing failed");
