syntax = "proto3";
package hbb;

message EncodedVideoFrame {
  bytes data = 1;
  bool key = 2;
  int64 pts = 3;
}

message EncodedVideoFrames { repeated EncodedVideoFrame frames = 1; }

message RGB { bool compress = 1; }

// planes data send directly in binary for better use arraybuffer on web
message YUV {
  bool compress = 1;
  int32 stride = 2;
}

enum Chroma {
  I420 = 0;
  I444 = 1;
}

message VideoFrame {
  oneof union {
    EncodedVideoFrames vp9s = 6;
    RGB rgb = 7;
    YUV yuv = 8;
    EncodedVideoFrames h264s = 10;
    EncodedVideoFrames h265s = 11;
    EncodedVideoFrames vp8s = 12;
    EncodedVideoFrames av1s = 13;
  }
  int32 display = 14;
}

message IdPk {
  string id = 1;
  bytes pk = 2;
}

message DisplayInfo {
  sint32 x = 1;
  sint32 y = 2;
  int32 width = 3;
  int32 height = 4;
  string name = 5;
  bool online = 6;
  bool cursor_embedded = 7;
  Resolution original_resolution = 8;
  double scale = 9;
}

message PortForward {
  string host = 1;
  int32 port = 2;
}

message FileTransfer {
  string dir = 1;
  bool show_hidden = 2;
}

message ViewCamera {}

message OSLogin {
  string username = 1;
  string password = 2;
}

message LoginRequest {
  string username = 1;
  bytes password = 2;
  string my_id = 4;
  string my_name = 5;
  OptionMessage option = 6;
  oneof union {
    FileTransfer file_transfer = 7;
    PortForward port_forward = 8;
    ViewCamera view_camera = 15;
    Terminal terminal = 16;
  }
  bool video_ack_required = 9;
  uint64 session_id = 10;
  string version = 11;
  OSLogin os_login = 12;
  string my_platform = 13;
  bytes hwid = 14;
  string avatar = 17;
}

message Terminal {
  string service_id = 1;  // Service ID for reconnecting to existing session
}

message Auth2FA {
  string code = 1;
  bytes hwid = 2;
}

message ChatMessage { string text = 1; }

message Features {
  bool privacy_mode = 1;
  bool terminal = 2;
}

message CodecAbility {
  bool vp8 = 1;
  bool vp9 = 2;
  bool av1 = 3;
  bool h264 = 4;
  bool h265 = 5;
}

message SupportedEncoding {
  bool h264 = 1;
  bool h265 = 2;
  bool vp8 = 3;
  bool av1 = 4;
  CodecAbility i444 = 5;
}

message PeerInfo {
  string username = 1;
  string hostname = 2;
  string platform = 3;
  repeated DisplayInfo displays = 4;
  int32 current_display = 5;
  bool sas_enabled = 6;
  string version = 7;
  Features features = 9;
  SupportedEncoding encoding = 10;
  SupportedResolutions resolutions = 11;
  // Use JSON's key-value format which is friendly for peer to handle.
  // NOTE: Only support one-level dictionaries (for peer to update), and the key is of type string.
  string platform_additions = 12;
  WindowsSessions windows_sessions = 13;
}

message WindowsSession {  
  uint32 sid = 1;  
  string name = 2;  
}  

message LoginResponse {
  oneof union {
    string error = 1;
    PeerInfo peer_info = 2;
  }
  bool enable_trusted_devices = 3;
}

message TouchScaleUpdate {
  // The delta scale factor relative to the previous scale.
  // delta * 1000
  // 0 means scale end
  int32 scale = 1;
}

message TouchPanStart {
  int32 x = 1;
  int32 y = 2;
}

message TouchPanUpdate {
  // The delta x position relative to the previous position.
  int32 x = 1;
  // The delta y position relative to the previous position.
  int32 y = 2;
}

message TouchPanEnd {
  int32 x = 1;
  int32 y = 2;
}

message TouchEvent {
  oneof union {
    TouchScaleUpdate scale_update = 1;
    TouchPanStart pan_start = 2;
    TouchPanUpdate pan_update = 3;
    TouchPanEnd pan_end = 4;
  }
}

message PointerDeviceEvent {
  oneof union {
    TouchEvent touch_event = 1;
  }
  repeated ControlKey modifiers = 2;
}

message MouseEvent {
  int32 mask = 1;
  sint32 x = 2;
  sint32 y = 3;
  repeated ControlKey modifiers = 4;
}

enum KeyboardMode{
  Legacy = 0;
  Map = 1;
  Translate = 2;
  Auto = 3;
}

enum ControlKey {
  Unknown = 0;
  Alt = 1;
  Backspace = 2;
  CapsLock = 3;
  Control = 4;
  Delete = 5;
  DownArrow = 6;
  End = 7;
  Escape = 8;
  F1 = 9;
  F10 = 10;
  F11 = 11;
  F12 = 12;
  F2 = 13;
  F3 = 14;
  F4 = 15;
  F5 = 16;
  F6 = 17;
  F7 = 18;
  F8 = 19;
  F9 = 20;
  Home = 21;
  LeftArrow = 22;
  /// meta key (also known as "windows"; "super"; and "command")
  Meta = 23;
  /// option key on macOS (alt key on Linux and Windows)
  Option = 24; // deprecated, use Alt instead
  PageDown = 25;
  PageUp = 26;
  Return = 27;
  RightArrow = 28;
  Shift = 29;
  Space = 30;
  Tab = 31;
  UpArrow = 32;
  Numpad0 = 33;
  Numpad1 = 34;
  Numpad2 = 35;
  Numpad3 = 36;
  Numpad4 = 37;
  Numpad5 = 38;
  Numpad6 = 39;
  Numpad7 = 40;
  Numpad8 = 41;
  Numpad9 = 42;
  Cancel = 43;
  Clear = 44;
  Menu = 45; // deprecated, use Alt instead
  Pause = 46;
  Kana = 47;
  Hangul = 48;
  Junja = 49;
  Final = 50;
  Hanja = 51;
  Kanji = 52;
  Convert = 53;
  Select = 54;
  Print = 55;
  Execute = 56;
  Snapshot = 57;
  Insert = 58;
  Help = 59;
  Sleep = 60;
  Separator = 61;
  Scroll = 62;
  NumLock = 63;
  RWin = 64;
  Apps = 65;
  Multiply = 66;
  Add = 67;
  Subtract = 68;
  Decimal = 69;
  Divide = 70;
  Equals = 71;
  NumpadEnter = 72;
  RShift = 73;
  RControl = 74;
  RAlt = 75;
  VolumeMute = 76; // mainly used on mobile devices as controlled side
  VolumeUp = 77;
  VolumeDown = 78;
  Power = 79; // mainly used on mobile devices as controlled side
  CtrlAltDel = 100;
  LockScreen = 101;
}

message KeyEvent {
  // `down` indicates the key's state(down or up).
  bool down = 1;
  // `press` indicates a click event(down and up).
  bool press = 2;
  oneof union {
    ControlKey control_key = 3;
    // position key code. win: scancode, linux: key code, macos: key code
    uint32 chr = 4;
    uint32 unicode = 5;
    string seq = 6;
    // high word. virtual keycode
    // low word. unicode
    uint32 win2win_hotkey = 7;
  }
  repeated ControlKey modifiers = 8;
  KeyboardMode mode = 9;
}

message CursorData {
  uint64 id = 1;
  sint32 hotx = 2;
  sint32 hoty = 3;
  int32 width = 4;
  int32 height = 5;
  bytes colors = 6;
}

message CursorPosition {
  sint32 x = 1;
  sint32 y = 2;
}

message Hash {
  string salt = 1;
  string challenge = 2;
}

enum ClipboardFormat {
  Text = 0;
  Rtf = 1;
  Html = 2;
  ImageRgba = 21;
  ImagePng = 22;
  ImageSvg = 23;
  Special = 31;
}

message Clipboard {
  bool compress = 1;
  bytes content = 2;
  int32 width = 3;
  int32 height = 4;
  ClipboardFormat format = 5;
  // Special format name, only used when format is Special.
  string special_name = 6;
}

message MultiClipboards { repeated Clipboard clipboards = 1; }

enum FileType {
  Dir = 0;
  DirLink = 2;
  DirDrive = 3;
  File = 4;
  FileLink = 5;
}

message FileEntry {
  FileType entry_type = 1;
  string name = 2;
  bool is_hidden = 3;
  uint64 size = 4;
  uint64 modified_time = 5;
}

message FileDirectory {
  int32 id = 1;
  string path = 2;
  repeated FileEntry entries = 3;
}

message ReadDir {
  string path = 1;
  bool include_hidden = 2;
}

message ReadEmptyDirs {
  string path = 1;
  bool include_hidden = 2;
}

message ReadEmptyDirsResponse {
  string path = 1;
  repeated FileDirectory empty_dirs = 2;
}

message ReadAllFiles {
  int32 id = 1;
  string path = 2;
  bool include_hidden = 3;
}

message FileRename {
  int32 id = 1;
  string path = 2;
  string new_name = 3;
}

message FileAction {
  oneof union {
    ReadDir read_dir = 1;
    FileTransferSendRequest send = 2;
    FileTransferReceiveRequest receive = 3;
    FileDirCreate create = 4;
    FileRemoveDir remove_dir = 5;
    FileRemoveFile remove_file = 6;
    ReadAllFiles all_files = 7;
    FileTransferCancel cancel = 8;
    FileTransferSendConfirmRequest send_confirm = 9;
    FileRename rename = 10;
    ReadEmptyDirs read_empty_dirs = 11;
  }
}

message FileTransferCancel { int32 id = 1; }

message FileResponse {
  oneof union {
    FileDirectory dir = 1;
    FileTransferBlock block = 2;
    FileTransferError error = 3;
    FileTransferDone done = 4;
    FileTransferDigest digest = 5;
    ReadEmptyDirsResponse empty_dirs = 6;
  }
}

message FileTransferDigest {
  int32 id = 1;
  sint32 file_num = 2;
  uint64 last_modified = 3;
  uint64 file_size = 4;
  bool is_upload = 5;
  bool is_identical = 6;
  uint64 transferred_size = 7; // For resume. Indicates the size of the file already transferred
  bool is_resume = 8;          // For resume. Indicates if the transfer is a resume.
                               // `is_resume` can let the controlled side know whether to check the `.digest` file.
                               // When `is_resume` is false, `.digest` exists, the same file does not exist,
                               // the controlled side should not check `.digest`, it should confirm with a new transfer request.
}

message FileTransferBlock {
  int32 id = 1;
  sint32 file_num = 2;
  bytes data = 3;
  bool compressed = 4;
  uint32 blk_id = 5;
}

message FileTransferError {
  int32 id = 1;
  string error = 2;
  sint32 file_num = 3;
}

message FileTransferSendRequest {
  int32 id = 1;
  string path = 2;
  bool include_hidden = 3;
  int32 file_num = 4;

  enum FileType {
    Generic = 0;
    Printer = 1;
  }
  FileType file_type = 5;
}

message FileTransferSendConfirmRequest {
  int32 id = 1;
  sint32 file_num = 2;
  oneof union {
    bool skip = 3;
    uint32 offset_blk = 4;
  }
}

message FileTransferDone {
  int32 id = 1;
  sint32 file_num = 2;
}

message FileTransferReceiveRequest {
  int32 id = 1;
  string path = 2; // path written to
  repeated FileEntry files = 3;
  int32 file_num = 4;
  uint64 total_size = 5;
}

message FileRemoveDir {
  int32 id = 1;
  string path = 2;
  bool recursive = 3;
}

message FileRemoveFile {
  int32 id = 1;
  string path = 2;
  sint32 file_num = 3;
}

message FileDirCreate {
  int32 id = 1;
  string path = 2;
}

// main logic from freeRDP
message CliprdrMonitorReady {
}

message CliprdrFormat {
  int32 id = 2;
  string format = 3;
}

message CliprdrServerFormatList {
  repeated CliprdrFormat formats = 2;
}

message CliprdrServerFormatListResponse {
  int32 msg_flags = 2;
}

message CliprdrServerFormatDataRequest {
  int32 requested_format_id = 2;
}

message CliprdrServerFormatDataResponse {
  int32 msg_flags = 2;
  bytes format_data = 3;
}

message CliprdrFileContentsRequest {
  int32 stream_id = 2;
  int32 list_index = 3;
  int32 dw_flags = 4;
  int32 n_position_low = 5;
  int32 n_position_high = 6;
  int32 cb_requested = 7;
  bool have_clip_data_id = 8;
  int32 clip_data_id = 9;
}

message CliprdrFileContentsResponse {
  int32 msg_flags = 3;
  int32 stream_id = 4;
  bytes requested_data = 5;
}

// Try empty clipboard in the following case(Windows only):
// 1. `A`(Windows) -> `B`, `C`
// 2. Copy in `A, file clipboards on `B` and `C` are updated.
// 3. Copy in `B`.
// `A` should tell `C` to empty the file clipboard.
message CliprdrTryEmpty {
}

// Clipobard file message for audit.
message CliprdrFile {
  string name = 1;
  uint64 size = 2;
}

message CliprdrFiles {
  repeated CliprdrFile files = 1;
}

message Cliprdr {
  oneof union {
    CliprdrMonitorReady ready = 1;
    CliprdrServerFormatList format_list = 2;
    CliprdrServerFormatListResponse format_list_response = 3;
    CliprdrServerFormatDataRequest format_data_request = 4;
    CliprdrServerFormatDataResponse format_data_response = 5;
    CliprdrFileContentsRequest file_contents_request = 6;
    CliprdrFileContentsResponse file_contents_response = 7;
    CliprdrTryEmpty try_empty = 8;
    CliprdrFiles files = 9;
  }
}

message Resolution {
  int32 width = 1;
  int32 height = 2;
}

message DisplayResolution {
  int32 display = 1;
  Resolution resolution = 2;
}

message SupportedResolutions { repeated Resolution resolutions = 1; }

message SwitchDisplay {
  int32 display = 1;
  sint32 x = 2;
  sint32 y = 3;
  int32 width = 4;
  int32 height = 5;
  bool cursor_embedded = 6;
  SupportedResolutions resolutions = 7;
  // Do not care about the origin point for now.
  Resolution original_resolution = 8;
}

message CaptureDisplays {
  repeated int32 add = 1;
  repeated int32 sub = 2;
  repeated int32 set = 3;
}

message ToggleVirtualDisplay {
  int32 display = 1;
  bool on = 2;
}

message TogglePrivacyMode {
  string impl_key = 1;
  bool on = 2;
}

message PermissionInfo {
  enum Permission {
    Keyboard = 0;
    Clipboard = 2;
    Audio = 3;
    File = 4;
    Restart = 5;
    Recording = 6;
    BlockInput = 7;
    PrivacyMode = 8;
  }

  Permission permission = 1;
  bool enabled = 2;
}

enum ImageQuality {
  NotSet = 0;
  Low = 2;
  Balanced = 3;
  Best = 4;
}

message SupportedDecoding {
  enum PreferCodec {
    Auto = 0;
    VP9 = 1;
    H264 = 2;
    H265 = 3;
    VP8 = 4;
    AV1 = 5;
  }

  int32 ability_vp9 = 1;
  int32 ability_h264 = 2;
  int32 ability_h265 = 3;
  PreferCodec prefer = 4;
  int32 ability_vp8 = 5;
  int32 ability_av1 = 6;
  CodecAbility i444 = 7;
  Chroma prefer_chroma = 8;
}

message OptionMessage {
  enum BoolOption {
    NotSet = 0;
    No = 1;
    Yes = 2;
  }
  ImageQuality image_quality = 1;
  BoolOption lock_after_session_end = 2;
  BoolOption show_remote_cursor = 3;
  BoolOption privacy_mode = 4;
  BoolOption block_input = 5;
  int32 custom_image_quality = 6;
  BoolOption disable_audio = 7;
  BoolOption disable_clipboard = 8;
  BoolOption enable_file_transfer = 9;
  SupportedDecoding supported_decoding = 10;
  int32 custom_fps = 11;
  BoolOption disable_keyboard = 12;
// Position 13 is used for Resolution. Remove later.
// Resolution custom_resolution = 13;
// BoolOption support_windows_specific_session = 14;
  // starting from 15 please, do not use removed fields
  BoolOption follow_remote_cursor = 15;
  BoolOption follow_remote_window = 16;
  BoolOption disable_camera = 17;
  BoolOption terminal_persistent = 18;
  BoolOption show_my_cursor = 19;
}

message TestDelay {
  int64 time = 1;
  bool from_client = 2;
  uint32 last_delay = 3;
  uint32 target_bitrate = 4;
}

message PublicKey {
  bytes asymmetric_value = 1;
  bytes symmetric_value = 2;
}

message SignedId { bytes id = 1; }

message AudioFormat {
  uint32 sample_rate = 1;
  uint32 channels = 2;
}

message AudioFrame { 
  bytes data = 1; 
}

// Notify peer to show message box.
message MessageBox {
  // Message type. Refer to flutter/lib/common.dart/msgBox().
  string msgtype = 1;
  string title = 2;
  // English
  string text = 3;
  // If not empty, msgbox provides a button to following the link.
  // The link here can't be directly http url.
  // It must be the key of http url configed in peer side or "rustdesk://*" (jump in app).
  string link = 4;
}

message BackNotification {
  // no need to consider block input by someone else
  enum BlockInputState {
    BlkStateUnknown = 0;
    BlkOnSucceeded = 2;
    BlkOnFailed = 3;
    BlkOffSucceeded = 4;
    BlkOffFailed = 5;
  }
  enum PrivacyModeState {
    PrvStateUnknown = 0;
    // Privacy mode on by someone else
    PrvOnByOther = 2;
    // Privacy mode is not supported on the remote side
    PrvNotSupported = 3;
    // Privacy mode on by self
    PrvOnSucceeded = 4;
    // Privacy mode on by self, but denied
    PrvOnFailedDenied = 5;
    // Some plugins are not found
    PrvOnFailedPlugin = 6;
    // Privacy mode on by self, but failed
    PrvOnFailed = 7;
    // Privacy mode off by self
    PrvOffSucceeded = 8;
    // Ctrl + P
    PrvOffByPeer = 9;
    // Privacy mode off by self, but failed
    PrvOffFailed = 10;
    PrvOffUnknown = 11;
  }

  oneof union {
    PrivacyModeState privacy_mode_state = 1;
    BlockInputState block_input_state = 2;
  }
  // Supplementary message, for "PrvOnFailed" and "PrvOffFailed"
  string details = 3;
  // The key of the implementation
  string impl_key = 4;
}

message ElevationRequestWithLogon {
  string username = 1;
  string password = 2;
}

message ElevationRequest {
  oneof union {
    bool direct = 1;
    ElevationRequestWithLogon logon = 2;
  }
}

message SwitchSidesRequest {
  bytes uuid = 1;
}

message SwitchSidesResponse {
  bytes uuid = 1;
  LoginRequest lr = 2;
}

message SwitchBack {}

message PluginRequest {
  string id = 1;
  bytes content = 2;
}

message PluginFailure {
  string id = 1;
  string name = 2;
  string msg = 3;
}

message WindowsSessions {
  repeated WindowsSession sessions = 1;
  uint32 current_sid = 2;
}

// Query messages from peer.
message MessageQuery {
  // The SwitchDisplay message of the target display.
  // If the target display is not found, the message will be ignored.
  int32 switch_display = 1;
}

message Misc {
  oneof union {
    ChatMessage chat_message = 4;
    SwitchDisplay switch_display = 5;
    PermissionInfo permission_info = 6;
    OptionMessage option = 7;
    AudioFormat audio_format = 8;
    string close_reason = 9;
    bool refresh_video = 10;
    bool video_received = 12;
    BackNotification back_notification = 13;
    bool restart_remote_device = 14;
    bool uac = 15;
    bool foreground_window_elevated = 16;
    bool stop_service = 17;
    ElevationRequest elevation_request = 18;
    string elevation_response = 19;
    bool portable_service_running = 20;
    SwitchSidesRequest switch_sides_request = 21;
    SwitchBack switch_back = 22;
    // Deprecated since 1.2.4, use `change_display_resolution` (36) instead.
    // But we must keep it for compatibility when peer version < 1.2.4.
    Resolution change_resolution = 24;
    PluginRequest plugin_request = 25;
    PluginFailure plugin_failure = 26;
    uint32 full_speed_fps = 27; // deprecated
    uint32 auto_adjust_fps = 28;
    bool client_record_status = 29;
    CaptureDisplays capture_displays = 30;
    int32 refresh_video_display = 31;
    ToggleVirtualDisplay toggle_virtual_display = 32;
    TogglePrivacyMode toggle_privacy_mode = 33;
    SupportedEncoding supported_encoding = 34;
    uint32 selected_sid = 35;
    DisplayResolution change_display_resolution = 36;
    MessageQuery message_query = 37;
    int32 follow_current_display = 38;
  }
}

message VoiceCallRequest {
  int64 req_timestamp = 1;
  // Indicates whether the request is a connect action or a disconnect action.
  bool is_connect = 2;
}

message VoiceCallResponse {
  bool accepted = 1;
  int64 req_timestamp = 2; // Should copy from [VoiceCallRequest::req_timestamp].
  int64 ack_timestamp = 3;
}

message ScreenshotRequest {
  int32 display = 1;
  // sid is the session id on the controlling side
  // It is used to forward the message to the correct remote (session) window.
  string sid = 2;
}

message ScreenshotResponse {
  string sid = 1;
  // empty if success
  string msg = 2;
  bytes data = 3;
}

// Terminal messages - standalone feature like FileAction
message OpenTerminal {
  int32 terminal_id = 1;  // 0 for default terminal
  uint32 rows = 2;
  uint32 cols = 3;
}

message ResizeTerminal {
  int32 terminal_id = 1;
  uint32 rows = 2;
  uint32 cols = 3;
}

message TerminalData {
  int32 terminal_id = 1;
  bytes data = 2;
  bool compressed = 3;
}

message CloseTerminal {
  int32 terminal_id = 1;
}

message TerminalAction {
  oneof union {
    OpenTerminal open = 1;
    TerminalData data = 2;
    ResizeTerminal resize = 3;
    CloseTerminal close = 4;
  }
}

message TerminalOpened {
  int32 terminal_id = 1;
  bool success = 2;
  string message = 3;
  uint32 pid = 4;
  string service_id = 5;  // Service ID for persistent sessions
  repeated int32 persistent_sessions = 6; // Used to restore the persistent sessions.
  bool replay_terminal_output = 7; // Whether the next data response replays buffered terminal output.
}

message TerminalClosed {
  int32 terminal_id = 1;
  int32 exit_code = 2;
}

message TerminalError {
  int32 terminal_id = 1;
  string message = 2;
}

message TerminalResponse {
  oneof union {
    TerminalOpened opened = 1;
    TerminalData data = 2;
    TerminalClosed closed = 3;
    TerminalError error = 4;
  }
}

message Message {
  oneof union {
    SignedId signed_id = 3;
    PublicKey public_key = 4;
    TestDelay test_delay = 5;
    VideoFrame video_frame = 6;
    LoginRequest login_request = 7;
    LoginResponse login_response = 8;
    Hash hash = 9;
    MouseEvent mouse_event = 10;
    AudioFrame audio_frame = 11;
    CursorData cursor_data = 12;
    CursorPosition cursor_position = 13;
    uint64 cursor_id = 14;
    KeyEvent key_event = 15;
    Clipboard clipboard = 16;
    FileAction file_action = 17;
    FileResponse file_response = 18;
    Misc misc = 19;
    Cliprdr cliprdr = 20;
    MessageBox message_box = 21;
    SwitchSidesResponse switch_sides_response = 22;
    VoiceCallRequest voice_call_request = 23;
    VoiceCallResponse voice_call_response = 24;
    PeerInfo peer_info = 25;
    PointerDeviceEvent pointer_device_event = 26;
    Auth2FA auth_2fa = 27;
    MultiClipboards multi_clipboards = 28;
    ScreenshotRequest screenshot_request = 29;
    ScreenshotResponse screenshot_response= 30;
    TerminalAction terminal_action = 31;
    TerminalResponse terminal_response = 32;
  }
}
