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
19 changes: 19 additions & 0 deletions docs/DDIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,25 @@ and name keeps its original id. Pending requests are stored in
`ddial_station_requests.dat` next to the member files and rewritten
atomically whenever they change.

### Outbound request tracking

Operators can submit the same request without putting `@request:` in the
reconnecting relay configuration:

- `/ddial request <host> <port> <station-name>` opens a separate one-shot
connection, waits for the password prompt, sends the request and closes.
It does not change the configured DDial relay or trigger its reconnect
loop.
- `/ddial request-status` shows the tracked remote request id, station name
and hub address.
- `/ddial request-cancel` clears the local tracking record. It does not
delete the request from the remote hub; that hub's operator must deny it.

The last outbound request is stored in `ddial_outbound_request.dat` next to
the member files and restored by reading that file. A new request requires
cancelling the previous local tracking first. After approval, use the issued
key with `/ddial connect` or `CHATTER_DDIAL_KEY` as usual.

Keys are stored as PBKDF2-SHA256 hashes in `ddial_station_keys.tsv` next to
the member files (mode 0600).

Expand Down
144 changes: 144 additions & 0 deletions src/host/core/command_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,150 @@ static const session_command_message_t kSessionCommandMessages[] = {
[SESSION_UI_LANGUAGE_PL] = "Zatwierdzono zgłoszenie stacji #%u. Klucz stacji #%u dla „%s”: %s (widoczny tylko raz; przekaż go operatorowi tej stacji)",
},
},
{
"No outbound station request is being tracked.",
{
[SESSION_UI_LANGUAGE_KO] = "추적 중인 발신 스테이션 요청이 없습니다.",
[SESSION_UI_LANGUAGE_JP] = "追跡中の送信ステーション要求はありません。",
[SESSION_UI_LANGUAGE_ZH] = "没有正在跟踪的出站站点请求。",
[SESSION_UI_LANGUAGE_RU] = "Исходящий запрос станции не отслеживается.",
[SESSION_UI_LANGUAGE_DE] = "Keine ausgehende Stationsanfrage wird verfolgt.",
[SESSION_UI_LANGUAGE_FR] = "Aucune demande de station sortante n'est suivie.",
[SESSION_UI_LANGUAGE_PL] = "Nie śledzono wychodzącego zgłoszenia stacji.",
},
},
{
"Could not read outbound station request tracking.",
{
[SESSION_UI_LANGUAGE_KO] = "발신 스테이션 요청 추적 정보를 읽지 못했습니다.",
[SESSION_UI_LANGUAGE_JP] = "送信ステーション要求の追跡情報を読めませんでした。",
[SESSION_UI_LANGUAGE_ZH] = "无法读取出站站点请求跟踪信息。",
[SESSION_UI_LANGUAGE_RU] = "Не удалось прочитать данные отслеживания исходящего запроса.",
[SESSION_UI_LANGUAGE_DE] = "Ausgehende Stationsanfrage konnte nicht gelesen werden.",
[SESSION_UI_LANGUAGE_FR] = "Impossible de lire le suivi de la demande sortante.",
[SESSION_UI_LANGUAGE_PL] = "Nie udało się odczytać śledzenia wychodzącego zgłoszenia.",
},
},
{
"Tracked outbound station request:",
{
[SESSION_UI_LANGUAGE_KO] = "추적 중인 발신 스테이션 요청:",
[SESSION_UI_LANGUAGE_JP] = "追跡中の送信ステーション要求:",
[SESSION_UI_LANGUAGE_ZH] = "正在跟踪的出站站点请求:",
[SESSION_UI_LANGUAGE_RU] = "Отслеживаемый исходящий запрос станции:",
[SESSION_UI_LANGUAGE_DE] = "Verfolgte ausgehende Stationsanfrage:",
[SESSION_UI_LANGUAGE_FR] = "Demande de station sortante suivie :",
[SESSION_UI_LANGUAGE_PL] = "Śledzone wychodzące zgłoszenie stacji:",
},
},
{
"Could not save outbound station request tracking.",
{
[SESSION_UI_LANGUAGE_KO] = "발신 스테이션 요청 추적 정보를 저장하지 못했습니다.",
[SESSION_UI_LANGUAGE_JP] = "送信ステーション要求の追跡情報を保存できませんでした。",
[SESSION_UI_LANGUAGE_ZH] = "无法保存出站站点请求跟踪信息。",
[SESSION_UI_LANGUAGE_RU] = "Не удалось сохранить данные отслеживания исходящего запроса.",
[SESSION_UI_LANGUAGE_DE] = "Ausgehende Stationsanfrage konnte nicht gespeichert werden.",
[SESSION_UI_LANGUAGE_FR] = "Impossible d'enregistrer le suivi de la demande sortante.",
[SESSION_UI_LANGUAGE_PL] = "Nie udało się zapisać śledzenia wychodzącego zgłoszenia.",
},
},
{
"Outbound request tracking cleared; the remote hub request is unchanged.",
{
[SESSION_UI_LANGUAGE_KO] = "발신 요청 추적을 지웠습니다. 원격 허브의 요청은 변경되지 않습니다.",
[SESSION_UI_LANGUAGE_JP] = "送信要求の追跡を消去しました。リモートハブ側の要求は変更されません。",
[SESSION_UI_LANGUAGE_ZH] = "已清除出站请求跟踪;远程中心上的请求保持不变。",
[SESSION_UI_LANGUAGE_RU] = "Локальное отслеживание очищено; запрос на удалённом хабе не изменён.",
[SESSION_UI_LANGUAGE_DE] = "Lokale Anfragenverfolgung gelöscht; die Anfrage beim entfernten Hub bleibt unverändert.",
[SESSION_UI_LANGUAGE_FR] = "Suivi local effacé ; la demande sur le hub distant reste inchangée.",
[SESSION_UI_LANGUAGE_PL] = "Wyczyszczono lokalne śledzenie; zgłoszenie w zdalnym koncentratorze pozostaje bez zmian.",
},
},
{
"Usage: /ddial request <host> <port> <station-name>",
{
[SESSION_UI_LANGUAGE_KO] = "사용법: /ddial request <호스트> <포트> <스테이션 이름>",
[SESSION_UI_LANGUAGE_JP] = "使い方: /ddial request <ホスト> <ポート> <ステーション名>",
[SESSION_UI_LANGUAGE_ZH] = "用法:/ddial request <主机> <端口> <站点名称>",
[SESSION_UI_LANGUAGE_RU] = "Использование: /ddial request <хост> <порт> <имя станции>",
[SESSION_UI_LANGUAGE_DE] = "Verwendung: /ddial request <Host> <Port> <Stationsname>",
[SESSION_UI_LANGUAGE_FR] = "Utilisation : /ddial request <hôte> <port> <nom-station>",
[SESSION_UI_LANGUAGE_PL] = "Użycie: /ddial request <host> <port> <nazwa-stacji>",
},
},
{
"Station request #%u recorded at %s:%lu for '%s'.",
{
[SESSION_UI_LANGUAGE_KO] = "스테이션 요청 #%u을(를) %s:%lu에 '%s' 이름으로 등록했습니다.",
[SESSION_UI_LANGUAGE_JP] = "ステーション要求 #%u を %s:%lu に '%s' として登録しました。",
[SESSION_UI_LANGUAGE_ZH] = "站点请求 #%u 已在 %s:%lu 为 '%s' 登记。",
[SESSION_UI_LANGUAGE_RU] = "Запрос станции #%u зарегистрирован на %s:%lu для «%s».",
[SESSION_UI_LANGUAGE_DE] = "Stationsanfrage #%u bei %s:%lu für „%s“ registriert.",
[SESSION_UI_LANGUAGE_FR] = "Demande de station #%u enregistrée sur %s:%lu pour « %s ».",
[SESSION_UI_LANGUAGE_PL] = "Zarejestrowano zgłoszenie stacji #%u w %s:%lu dla „%s”.",
},
},
{
"Remote station request #%u was recorded, but local tracking could not be saved.",
{
[SESSION_UI_LANGUAGE_KO] = "원격 스테이션 요청 #%u은(는) 등록됐지만 로컬 추적 정보를 저장하지 못했습니다.",
[SESSION_UI_LANGUAGE_JP] = "リモートステーション要求 #%u は登録されましたが、ローカル追跡情報を保存できませんでした。",
[SESSION_UI_LANGUAGE_ZH] = "远程站点请求 #%u 已登记,但无法保存本地跟踪信息。",
[SESSION_UI_LANGUAGE_RU] = "Запрос #%u зарегистрирован удалённо, но локальное отслеживание не сохранено.",
[SESSION_UI_LANGUAGE_DE] = "Entfernte Stationsanfrage #%u registriert, lokale Verfolgung konnte nicht gespeichert werden.",
[SESSION_UI_LANGUAGE_FR] = "Demande distante #%u enregistrée, mais le suivi local n'a pas pu être sauvegardé.",
[SESSION_UI_LANGUAGE_PL] = "Zdalne zgłoszenie #%u zapisano, ale lokalnego śledzenia nie udało się zapisać.",
},
},
{
"An outbound station request is already tracked; check request-status or cancel it first.",
{
[SESSION_UI_LANGUAGE_KO] = "이미 추적 중인 발신 요청이 있습니다. request-status를 확인하거나 먼저 취소하세요.",
[SESSION_UI_LANGUAGE_JP] = "すでに送信要求を追跡中です。request-status を確認するか、先に取り消してください。",
[SESSION_UI_LANGUAGE_ZH] = "已有一个正在跟踪的出站请求;请先查看 request-status 或取消它。",
[SESSION_UI_LANGUAGE_RU] = "Исходящий запрос уже отслеживается; проверьте request-status или сначала отмените его.",
[SESSION_UI_LANGUAGE_DE] = "Eine ausgehende Anfrage wird bereits verfolgt; request-status prüfen oder zuerst abbrechen.",
[SESSION_UI_LANGUAGE_FR] = "Une demande sortante est déjà suivie ; consultez request-status ou annulez-la d'abord.",
[SESSION_UI_LANGUAGE_PL] = "Wychodzące zgłoszenie jest już śledzone; sprawdź request-status lub najpierw je anuluj.",
},
},
{
"Another outbound station request is already in progress.",
{
[SESSION_UI_LANGUAGE_KO] = "다른 발신 스테이션 요청이 이미 진행 중입니다.",
[SESSION_UI_LANGUAGE_JP] = "別の送信ステーション要求がすでに進行中です。",
[SESSION_UI_LANGUAGE_ZH] = "另一个出站站点请求已在处理中。",
[SESSION_UI_LANGUAGE_RU] = "Другой исходящий запрос станции уже выполняется.",
[SESSION_UI_LANGUAGE_DE] = "Eine andere ausgehende Stationsanfrage läuft bereits.",
[SESSION_UI_LANGUAGE_FR] = "Une autre demande de station sortante est déjà en cours.",
[SESSION_UI_LANGUAGE_PL] = "Inne wychodzące zgłoszenie stacji jest już w toku.",
},
},
{
"Could not read or save outbound station request tracking.",
{
[SESSION_UI_LANGUAGE_KO] = "발신 스테이션 요청 추적 정보를 읽거나 저장하지 못했습니다.",
[SESSION_UI_LANGUAGE_JP] = "送信ステーション要求の追跡情報を読み書きできませんでした。",
[SESSION_UI_LANGUAGE_ZH] = "无法读取或保存出站站点请求跟踪信息。",
[SESSION_UI_LANGUAGE_RU] = "Не удалось прочитать или сохранить отслеживание исходящего запроса.",
[SESSION_UI_LANGUAGE_DE] = "Ausgehende Stationsanfrage konnte nicht gelesen oder gespeichert werden.",
[SESSION_UI_LANGUAGE_FR] = "Impossible de lire ou d'enregistrer le suivi de la demande sortante.",
[SESSION_UI_LANGUAGE_PL] = "Nie udało się odczytać lub zapisać śledzenia wychodzącego zgłoszenia.",
},
},
{
"Could not register the request with the remote station hub.",
{
[SESSION_UI_LANGUAGE_KO] = "원격 스테이션 허브에 요청을 등록하지 못했습니다.",
[SESSION_UI_LANGUAGE_JP] = "リモートステーションハブに要求を登録できませんでした。",
[SESSION_UI_LANGUAGE_ZH] = "无法在远程站点中心登记请求。",
[SESSION_UI_LANGUAGE_RU] = "Не удалось зарегистрировать запрос на удалённом хабе.",
[SESSION_UI_LANGUAGE_DE] = "Anfrage konnte beim entfernten Stations-Hub nicht registriert werden.",
[SESSION_UI_LANGUAGE_FR] = "Impossible d'enregistrer la demande sur le hub distant.",
[SESSION_UI_LANGUAGE_PL] = "Nie udało się zarejestrować zgłoszenia w zdalnym koncentratorze.",
},
},
};

// Returns the message in the session's UI language, or the English text when
Expand Down
39 changes: 39 additions & 0 deletions src/host/core/help_entries.c
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,45 @@ static const session_help_entry_t kSessionHelpOperator[] = {
.label_arg_count = 0U,
.label_args = {},
},
{
.kind = SESSION_HELP_ENTRY_COMMAND,
.label = "ddial <request <host> <port> <station-name>|request-status|request-cancel>",
.description =
{
"Submit a one-shot station request without changing the DDial "
"relay. request-status shows saved tracking; request-cancel "
"clears only local tracking, not the remote request (operator "
"only).",
"DDial 중계 설정을 바꾸지 않고 스테이션 요청을 한 번 별냅니다. "
"request-status는 저장된 추적 정보를 보여주고, request-cancel은 "
"원격 요청이 아닌 로컬 추적만 지웁니다 (운영자 전용).",
"DDial 中継を変更せずにステーション要求を一度だけ送信します。"
"request-status は保存した追跡情報を表示し、request-cancel は"
"リモート要求ではなくローカル追跡だけを消去します"
"(オペレーター専用)。",
"在不更改 DDial 中继的情况下发送一次性站点请求。"
"request-status 显示已保存的跟踪信息;request-cancel 仅清除"
"本地跟踪,不删除远程请求(仅限管理员)。",
"Отправить одноразовый запрос станции без изменения ретрансляции "
"DDial. request-status показывает сохранённое отслеживание; "
"request-cancel очищает только локальное отслеживание, не "
"удалённый запрос (только оператор).",
"Einmalige Stationsanfrage senden, ohne das DDial-Relay zu "
"ändern. request-status zeigt die gespeicherte Verfolgung; "
"request-cancel löscht nur die lokale Verfolgung, nicht die "
"entfernte Anfrage (nur Operatoren).",
"Envoyer une demande de station unique sans modifier le relais "
"DDial. request-status affiche le suivi enregistré ; "
"request-cancel efface uniquement le suivi local, pas la "
"demande distante (opérateur uniquement).",
"Wyślij jednorazowe zgłoszenie stacji bez zmiany przekaźnika "
"DDial. request-status pokazuje zapisane śledzenie; "
"request-cancel czyści tylko lokalne śledzenie, nie zdalne "
"zgłoszenie (tylko operator).",
},
.label_arg_count = 0U,
.label_args = {},
},
{
.kind = SESSION_HELP_ENTRY_COMMAND,
.label = "resetpw <nickname>",
Expand Down
Loading
Loading