+static int inputfile_is_done(InputFile *ipf) {
+ if (!ipf) return 0;
+ if (ipf->inprogress) return 0; /* new article in the meantime */
+ if (ipf->fd >= 0); return 0; /* not had EOF */
+ return 1;
+}
+
+static void notice_processed(InputFile *ipf, const char *what,
+ const char *spec) {
+#define RCI_NOTHING(x) /* nothing */
+#define RCI_TRIPLE_FMT(x) " " #x "=" RCI_TRIPLE_FMT_BASE
+#define RCI_TRIPLE_VALS(x) RCI_TRIPLE_VALS_BASE(ipf->counts, .x)
+
+ info("processed %s%s offered=%d(ch%d,nc%d) accepted=%d(ch%d+nc%d)"
+ RESULT_COUNTS(RCI_NOTHING, RCI_TRIPLE_FMT)
+ ,
+ what,spec,
+ ipf->counts[art_Unchecked].sent + ipf->counts[art_Unsolicited].sent
+ , ipf->counts[art_Unchecked].sent, ipf->counts[art_Unsolicited].sent,
+ ipf->counts[art_Wanted].accepted + ipf->counts[art_Unsolicited].accepted
+ ,ipf->counts[art_Wanted].accepted,ipf->counts[art_Unsolicited].accepted
+ RESULT_COUNTS(RCI_NOTHING, RCI_TRIPLE_VALS)
+ );
+}
+
+static void statemc_check_backlog_done(void) {
+ InputFile *ipf= backlog_input_file();
+ if (!inputfile_is_done(ipf)) return;
+
+ const char *slash= strrchr(ipf->path, "/");
+ const char *leaf= slash ? slash+1 : ipf->path;
+ const char *under= strchr(slash, "_");
+ const char *rest= under ? under+1 : leaf;
+ if (!strncmp(rest,"backlog",7)) rest += 7;
+ notice_processed(ipf,"backlog:",rest);
+
+ close_input_file(ipf);
+ if (unlink(ipf->path)) {
+ if (errno != ENOENT)
+ sysdie("could not unlink processed backlog file %s", ipf->path);
+ warn("backlog file %s vanished while we were reading it"
+ " so we couldn't remove it (but it's done now, anyway)",
+ ipf->path);
+ }
+ free(ipf);
+ backlog_input_file= 0;
+ search_backlog_file();
+ return;
+}
+
+static void statemc_check_flushing_done(void) {
+ InputFile *ipf= flushing_input_file;
+ if (!inputfile_is_done(ipf)) return;
+
+ assert(sms==sm_SEPARATED || sms==sm_DROPPING);
+
+ notice_processed(ipf,"feedfile",0);
+
+ close_defer();
+
+ xunlink(path_flushing, "old flushing file");
+
+ close_input_file(flushing_input_file);
+ free(flushing_input_file);
+ flushing_input_file= 0;
+
+ if (sms==sm_SEPARATED) {
+ notice("flush complete");
+ SMS(NORMAL, 0, "flush complete");
+ } else if (sms==sm_DROPPING) {
+ SMS(DROPPED, 0, "old flush complete");
+ search_backlog_file();
+ notice("feed dropped, but will continue until backlog is finished");
+ }
+}
+
+static void *statemc_check_input_done(oop_source *lp, struct timeval now,
+ void *u) {
+ assert(!inputfile_is_done(main_input_file));
+ statemc_check_flushing_done();
+ statemc_check_backlog_done();
+ return OOP_CONTINUE;
+}
+
+static void queue_check_input_done(void) {
+ loop->on_time(loop, OOP_TIME_NOW, statemc_check_input_done, 0);
+}
+
+static void statemc_setstate(StateMachineState newsms, int periods,
+ const char *forlog, const char *why) {
+ sms= newsms;
+ sm_period_counter= periods;
+
+ const char *xtra= "";
+ switch (sms) {
+ case sm_FLUSHING: sm_FLUSHFAILED:
+ if (!main_input_file) xtra= "-ABSENT";
+ break;
+ case sm_SEPARATED: case sm_DROPPING:
+ xtra= flushing_input_file->fd >= 0 ? "-1" : "-2";
+ break;
+ default:;
+ }
+
+ if (periods) {
+ info("%s%s[%d] %s",forlog,xtra,periods,why);
+ } else {
+ info("%s%s %s",forlog,xtra,why);
+ }
+}
+
+/*---------- defer and backlog files ----------*/
+
+static void open_defer(void) {