From 2f2ec795757a9ea5e05e5c1d123d0cabfcb80511 Mon Sep 17 00:00:00 2001 From: PoliEcho Date: Mon, 14 Apr 2025 14:50:04 +0200 Subject: [PATCH] add cups printing function --- Makefile | 4 +- src/cups.cpp | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/cups.h | 9 +++ 3 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 src/cups.cpp create mode 100644 src/cups.h diff --git a/Makefile b/Makefile index d6917fb..baf0855 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Compiler and flags CPPC = g++ -CPPC_FLAGS = -std=c++23 -s -O3 -Wall -Wextra -Wno-write-strings -lncurses -lmenu -lform -DEBUG_FLAGS = -ggdb -std=c++23 -Wall -Wextra -Wno-write-strings -lncurses -lmenu -lform +CPPC_FLAGS = -std=c++23 -s -O3 -Wall -Wextra -Wno-write-strings -lncurses -lmenu -lform -lcups +DEBUG_FLAGS = -ggdb -std=c++23 -Wall -Wextra -Wno-write-strings -lncurses -lmenu -lform -lcups SRC_PATH := src diff --git a/src/cups.cpp b/src/cups.cpp new file mode 100644 index 0000000..e344ca4 --- /dev/null +++ b/src/cups.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include + +/** + * Displays a menu of available printers and prints content to the selected one + * @param content The text content to print + * @return true if printing was successful, false otherwise + */ +bool printDocument(const std::string& content) { + // Initialize variables + bool success = false; + cups_dest_t* dests = nullptr; + int num_dests = 0; + ITEM** menu_items = nullptr; + MENU* menu = nullptr; + WINDOW* menu_win = nullptr; + std::vector item_names; + std::vector item_descriptions; + + // Write content to a temporary file + std::string tempFileName = "/tmp/print_temp_ParaDocs.txt"; + std::ofstream tempFile(tempFileName); + if (!tempFile) { + return false; // Failed to create temp file + } + tempFile << content; + tempFile.close(); + + // Get printer destinations from CUPS + num_dests = cupsGetDests(&dests); + if (num_dests <= 0) { + remove(tempFileName.c_str()); + return false; // No printers available + } + + // Initialize ncurses + initscr(); + start_color(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + try { + // Allocate memory for menu items + menu_items = new ITEM*[num_dests + 1]; + + // Prepare menu items for each printer + for (int i = 0; i < num_dests; i++) { + // Create display name + std::string display_name; + if (dests[i].instance) { + display_name = std::string(dests[i].name) + "/" + dests[i].instance; + } else { + display_name = dests[i].name; + } + + // Allocate memory for name string + char* name_str = new char[display_name.length() + 1]; + std::strcpy(name_str, display_name.c_str()); + item_names.push_back(name_str); + + // Get description if available + const char* desc = + cupsGetOption("printer-info", dests[i].num_options, dests[i].options); + std::string description = desc ? desc : ""; + + // Allocate memory for description string + char* desc_str = new char[description.length() + 1]; + std::strcpy(desc_str, description.c_str()); + item_descriptions.push_back(desc_str); + + // Create menu item + menu_items[i] = new_item(name_str, desc_str); + if (!menu_items[i]) { + throw std::runtime_error("Failed to create menu item"); + } + } + menu_items[num_dests] = nullptr; // NULL-terminate the array + + // Create the menu + menu = new_menu(menu_items); + if (!menu) { + throw std::runtime_error("Failed to create menu"); + } + + // Set up menu window + int rows, cols; + getmaxyx(stdscr, rows, cols); + menu_win = newwin(rows - 4, cols - 4, 2, 2); + keypad(menu_win, TRUE); + + // Set menu window and sub window + set_menu_win(menu, menu_win); + set_menu_sub(menu, derwin(menu_win, rows - 6, cols - 6, 1, 1)); + set_menu_format(menu, rows - 8, 1); + set_menu_mark(menu, " * "); + + // Post the menu with instructions + mvprintw(0, 0, "Select a printer and press Enter:"); + mvprintw(rows - 2, 0, "Press q to cancel"); + refresh(); + post_menu(menu); + wrefresh(menu_win); + + // Menu interaction loop + int c; + while ((c = wgetch(menu_win)) != 'q') { + switch (c) { + case KEY_DOWN: + menu_driver(menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(menu, REQ_UP_ITEM); + break; + case 10: // Enter key + { + ITEM* cur = current_item(menu); + int index = item_index(cur); + + // Print the document to the selected printer + int job_id = + cupsPrintFile(dests[index].name, tempFileName.c_str(), + "Document from application", + dests[index].num_options, dests[index].options); + + if (job_id > 0) { + success = true; + mvprintw(rows - 1, 0, "Printing job %d submitted successfully", + job_id); + } else { + mvprintw(rows - 1, 0, "Error: %s", cupsLastErrorString()); + } + refresh(); + napms(2000); // Display message for 2 seconds + c = 'q'; // Exit the loop + goto exit_menu; + break; + } + } + wrefresh(menu_win); + } + } catch (const std::exception& e) { + mvprintw(0, 0, "Error: %s", e.what()); + refresh(); + napms(2000); + } +exit_menu: + + // Clean up resources + if (menu) { + unpost_menu(menu); + free_menu(menu); + } + + if (menu_items) { + for (int i = 0; i < num_dests && menu_items[i]; i++) { + free_item(menu_items[i]); + } + delete[] menu_items; + } + + // Free allocated strings + for (char* str : item_names) { + delete[] str; + } + for (char* str : item_descriptions) { + delete[] str; + } + + if (menu_win) { + delwin(menu_win); + } + + // End ncurses + endwin(); + + // Remove temp file + remove(tempFileName.c_str()); + + // Free CUPS destinations + cupsFreeDests(num_dests, dests); + + return success; +} diff --git a/src/cups.h b/src/cups.h new file mode 100644 index 0000000..93d3de5 --- /dev/null +++ b/src/cups.h @@ -0,0 +1,9 @@ +#include + +#ifndef PARADOCS_CUPS_H_ +#define PARADOCS_CUPS_H_ + + +bool printDocument(const std::string& content); + +#endif \ No newline at end of file