diff --git a/src/capt-command.c b/src/capt-command.c index c9f1642..7e1a69b 100644 --- a/src/capt-command.c +++ b/src/capt-command.c @@ -30,6 +30,8 @@ static uint8_t capt_iobuf[0x10000]; static size_t capt_iosize; +static cups_sc_status_t last_send_status = CUPS_SC_STATUS_NONE; +static bool sendrecv_started = false; static void capt_debug_buf(const char *level, size_t size) { @@ -202,3 +204,29 @@ void capt_multi_send(void) capt_iobuf[3] = HI(capt_iosize); capt_send_buf(); } + +void capt_cleanup(void) +{ + /* For use with handling job cancellations */ + if (sendrecv_started) { + + if (last_send_status != CUPS_SC_STATUS_OK) { + capt_send_buf(); + fprintf(stderr, "DEBUG: CAPT: finished interrupted send\n"); + } + + /* not else because recv cleanup is needed after finishing send */ + if (last_send_status == CUPS_SC_STATUS_OK) { + size_t bytes = 0x10000; + size_t bs = 64; + while(bytes > 0) { + bytes -= bs; + cupsBackChannelRead(NULL, bs, 0.01); + } + fprintf(stderr, "DEBUG: CAPT: finished interrupted recv\n"); + } + + capt_iosize = 0; + sendrecv_started = false; + } +} diff --git a/src/capt-command.h b/src/capt-command.h index bb807f8..1ca8f5a 100644 --- a/src/capt-command.h +++ b/src/capt-command.h @@ -63,3 +63,4 @@ void capt_sendrecv(uint16_t cmd, const void *buf, size_t size, void *reply, size void capt_multi_begin(uint16_t cmd); void capt_multi_add(uint16_t cmd, const void *data, size_t size); void capt_multi_send(void); +void capt_cleanup(void); diff --git a/src/printer.h b/src/printer.h index 296971b..5ae6939 100644 --- a/src/printer.h +++ b/src/printer.h @@ -51,6 +51,7 @@ struct printer_ops_s { void *band, size_t size, const void *pixels, unsigned line_size, unsigned num_lines); void (*send_band) (struct printer_state_s *state, const void *band, size_t size); + void (*cancel_cleanup) (struct printer_state_s *state); void (*wait_user) (struct printer_state_s *state); }; diff --git a/src/rastertocapt.c b/src/rastertocapt.c index 94d941f..894d523 100644 --- a/src/rastertocapt.c +++ b/src/rastertocapt.c @@ -40,10 +40,21 @@ struct band_list_s { size_t size; uint8_t data[]; }; + +/* printer and job state */ +const struct printer_ops_s *ops; +struct printer_state_s *state = NULL; +struct cached_page_s *cached_page = NULL; +cups_raster_t *raster; + +/* compressor state */ +uint8_t *linebuf = NULL; +uint8_t *bandbuf = NULL; +uint8_t *compbuf = NULL; + static inline size_t sizeof_struct_band_list_s(size_t size) { return sizeof(struct band_list_s) + size; } - static size_t center_pixels(size_t small, size_t large, unsigned bpp) { unsigned small_p; @@ -57,6 +68,43 @@ static size_t center_pixels(size_t small, size_t large, unsigned bpp) return bypp * ((large_p - small_p) / 2); } +static void free_cached_page(struct cached_page_s *cached_page) +{ + while (cached_page->bands) { + void *p = cached_page->bands; + cached_page->bands = cached_page->bands->next; + free(p); + } + free(cached_page); +} + +static void free_state(void) +{ + if (state) { + if (ops->free_state) + ops->free_state(state); + else + free(state); + state = NULL; + } +} + +static void free_buffers(void) +{ + if (compbuf) { + free(compbuf); + compbuf = NULL; + } + if (bandbuf) { + free(bandbuf); + bandbuf = NULL; + } + if (linebuf) { + free(linebuf); + linebuf = NULL; + } +} + static void compress_page_data(struct printer_state_s *state, struct cached_page_s *page, cups_raster_t *raster, @@ -64,9 +112,6 @@ static void compress_page_data(struct printer_state_s *state, { const struct page_dims_s *dims = &page->dims; const unsigned compsize = 2 * dims->line_size * dims->band_size; - uint8_t *linebuf = NULL; - uint8_t *bandbuf = NULL; - uint8_t *compbuf = NULL; struct band_list_s *last_band = NULL; unsigned i; @@ -146,12 +191,7 @@ static void compress_page_data(struct printer_state_s *state, for (i = dims->num_lines; i < header->cupsHeight; ++i) cupsRasterReadPixels(raster, linebuf, header->cupsBytesPerLine); - if (compbuf) - free(compbuf); - if (bandbuf) - free(bandbuf); - if (linebuf) - free(linebuf); + free_buffers(); } static void send_page_data(struct printer_state_s *state, const struct cached_page_s *page) @@ -165,14 +205,36 @@ static void send_page_data(struct printer_state_s *state, const struct cached_pa state->ops->send_band(state, band->data, band->size); } +static void do_cancel(int s) +{ + (void) s; + fprintf(stderr, "DEBUG: CAPT: begin job cancellation cleanup\n"); + + if (ops) + ops->cancel_cleanup(state); + + if (raster) { + cupsRasterClose(raster); + raster = NULL; + } + + free_buffers(); + + if (cached_page) { + free_cached_page(cached_page); + cached_page = NULL; + } + + if (state) + free_state(); + + fprintf(stderr, "DEBUG: CAPT: job cancellation cleanup complete\n"); + exit(1); +} + static void do_print(int fd) { - const struct printer_ops_s *ops; - struct printer_state_s *state = NULL; - struct cached_page_s *cached_page = NULL; bool in_job = false; - cups_raster_t *raster; - ops = printer_detect(); if (ops->alloc_state) @@ -269,19 +331,31 @@ static void do_print(int fd) fprintf(stderr, "ERROR: CAPT: no pages in job\n"); cupsRasterClose(raster); - - if (state) { - if (ops->free_state) - ops->free_state(state); - else - free(state); - state = NULL; - } + free_state(); } int main(int argc, char *argv[]) { + +#if POSIX_C_SOURCE >= 199309L + struct sigaction act_ign; + struct sigaction act_cancel; + + /* ignore SIGPIPE */ + act_ign.sa_handler = SIG_IGN; + sigemptyset(&act_ign.sa_mask); + sigaction(SIGPIPE, &act_ign, NULL); + /* handle SIGTERM */ + act_cancel.sa_handler = do_cancel(); + sigemptyset(&act_cancel.sa_mask); + sigaddset(&act_cancel.sa_mask, SIGINT); + sigaction(SIGTERM, &act_cancel, NULL); +#else + signal(SIGPIPE, SIG_IGN); + signal(SIGTERM, do_cancel); +#endif + int fd = 0; if (argc < 6 || argc > 7) { @@ -298,7 +372,6 @@ int main(int argc, char *argv[]) } fprintf(stderr, "DEBUG: CAPT: rastertocapt started\n"); - signal(SIGPIPE, SIG_IGN); do_print(fd); fprintf(stderr, "DEBUG: CAPT: rastertocapt finished\n");