Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ coverage/
*.zip
*.deb
*.rpm
v2/
11 changes: 11 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Unreleased]

### Fixed
- **Hardware Button Type: Server Terminal Duplicates and Printer Removal (2026-02-12)**
- Fixed bugs in Hardware zone that created duplicate server terminals and incorrectly removed shared printers
- **Bug 1: Duplicate Server Terminals**
- **Root Cause**: `FindServer()` assumed first terminal was always server but didn't properly search for existing servers or handle loaded settings with incorrect order
- **Solution**: Rewrote `FindServer()` to first search for terminal matching display hostname, then existing server terminals, ensure correct terminal is marked as server and moved to front, clear IsServer flags from others, and remove duplicate "Server" named terminals
- **Impact**: Server terminals are correctly identified, duplicates are prevented and cleaned up
- **Bug 2: Shared Printer Removal**
- **Root Cause**: When removing a terminal, associated printer was killed even if other terminals shared the same printer configuration
- **Solution**: Added `IsPrinterShared()` method to check if printer is used by multiple terminals, modified `KillRecord()` to only kill printer if not shared
- **Impact**: Printers are preserved when shared between terminals, only removed when truly no longer needed
- **Files modified**: `main/data/settings.cc`, `main/data/settings.hh`, `zone/hardware_zone.cc`
- **Hardware Button Type: Simplified Server Display Logic (2026-02-05)**
- Completely simplified the server display and terminal initialization logic
- **New Approach**: The FIRST terminal in the list is ALWAYS the server display
Expand Down
130 changes: 93 additions & 37 deletions main/data/settings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3920,6 +3920,20 @@ int Settings::Remove(PrinterInfo *pr)
return printer_list.Remove(pr);
}

bool Settings::IsPrinterShared(const genericChar* host, int port, TermInfo *exclude)
{
FnTrace("Settings::IsPrinterShared()");
for (TermInfo *ti = term_list.Head(); ti != nullptr; ti = ti->next)
{
if (ti == exclude) continue;
if (strcmp(ti->printer_host.Value(), host) == 0 && ti->printer_port == port)
{
return true;
}
}
return false;
}

int Settings::Remove(MoneyInfo *my)
{
FnTrace("Settings::Remove(MoneyInfo)");
Expand Down Expand Up @@ -4471,51 +4485,93 @@ TermInfo *Settings::FindServer(const genericChar* displaystr)
{
FnTrace("Settings::FindServer()");
TermInfo *ti = term_list.Head();
TermInfo *found = nullptr;

// The first terminal in the list is ALWAYS the server display
if (ti != nullptr)
// First, look for a terminal matching the displaystr
while (ti != nullptr)
{
// Ensure the first terminal is marked as server
if (!ti->IsServer())
if (strcmp(ti->display_host.Value(), displaystr) == 0)
{
ti->IsServer(1);
found = ti;
break;
}

// Remove any other terminals that were previously marked as server
// and have the default "Server" name (auto-created duplicates)
TermInfo *other = ti->next;
while (other != nullptr)
ti = ti->next;
}

// If not found, look for an existing server
if (found == nullptr)
{
ti = term_list.Head();
while (ti != nullptr)
{
TermInfo *next_other = other->next;
if (other->IsServer())
if (ti->IsServer())
{
other->IsServer(0);
found = ti;
break;
}
// Remove auto-created "Server" terminals that are duplicates
if (strcmp(other->name.Value(), "Server") == 0 &&
(other->display_host.empty() ||
strcmp(other->display_host.Value(), displaystr) == 0))
{
Remove(other);
delete other;
}
other = next_other;
ti = ti->next;
}

return ti;
}

// No terminals exist - create the server terminal
ti = new TermInfo;
ti->name.Set("Server");
ti->display_host.Clear();
ti->type = TERMINAL_NORMAL;
ti->printer_model = 0;
ti->printer_port = 0;
ti->IsServer(1);
AddFront(ti);

return ti;
}

// If still not found, use the first terminal or create one
if (found == nullptr)
{
ti = term_list.Head();
if (ti != nullptr)
{
found = ti;
}
else
{
// No terminals exist - create the server terminal
found = new TermInfo;
found->name.Set("Server");
found->display_host.Set(displaystr);
found->type = TERMINAL_NORMAL;
found->printer_model = 0;
found->printer_port = 0;
found->IsServer(1);
AddFront(found);
return found;
}
}

// Ensure the found terminal is marked as server and moved to front if not already
found->IsServer(1);
if (found != term_list.Head())
{
// Move to front
Remove(found);
AddFront(found);
}

// Clear IsServer from all others
ti = term_list.Head();
while (ti != nullptr)
{
if (ti != found)
{
ti->IsServer(0);
}
ti = ti->next;
}

// Remove auto-created duplicate "Server" terminals
ti = term_list.Head()->next; // Start from second
while (ti != nullptr)
{
TermInfo *next_ti = ti->next;
if (strcmp(ti->name.Value(), "Server") == 0 &&
(ti->display_host.empty() ||
strcmp(ti->display_host.Value(), displaystr) == 0))
{
Remove(ti);
delete ti;
}
ti = next_ti;
}

return found;
}

TermInfo *Settings::FindTerminal(const char* displaystr)
Expand Down
1 change: 1 addition & 0 deletions main/data/settings.hh
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ public:
int AddFront(TermInfo *ti);
int Remove(TermInfo *ti);
int TermReport(Terminal *t, Report *r);
bool IsPrinterShared(const genericChar* host, int port, TermInfo *exclude = nullptr);

// printer functions
PrinterInfo *PrinterList() { return printer_list.Head(); }
Expand Down
10 changes: 7 additions & 3 deletions zone/hardware_zone.cc
Original file line number Diff line number Diff line change
Expand Up @@ -539,10 +539,14 @@ int HardwareZone::KillRecord(Terminal *term, int record)
TermInfo *ti = settings->FindTermByRecord(record);
if (ti && !ti->IsServer())
{
// Check if the printer is shared by other terminals
if (!settings->IsPrinterShared(ti->printer_host.Value(), ti->printer_port, ti))
{
Printer *printer = ti->FindPrinter(db);
if (printer)
db->KillPrinter(printer);
}
settings->Remove(ti);
Printer *printer = ti->FindPrinter(db);
if (printer)
db->KillPrinter(printer);
Terminal *tmp = ti->FindTerm(db);
if (tmp)
tmp->kill_me = 1;
Expand Down