/**
 * Copyright (C) 2014-2016 Open Whisper Systems
 *
 * Licensed according to the LICENSE file in this repository.
 */

// iOS - since we use a modern proto-compiler, we must specify
// the legacy proto format.
syntax = "proto2";

// iOS - package name determines class prefix
package SignalServiceProtos;

option java_package = "org.whispersystems.signalservice.internal.push";
option java_outer_classname = "SignalServiceProtos";

message Envelope {
  enum Type {
    UNKNOWN                 = 0;
    CIPHERTEXT              = 1;
    KEY_EXCHANGE            = 2;
    PREKEY_BUNDLE           = 3;
    RECEIPT                 = 5;
    UNIDENTIFIED_SENDER     = 6;
    CLOSED_GROUP_CIPHERTEXT = 7; // Loki
    FALLBACK_MESSAGE        = 101; // Loki: Encrypted using the fallback session cipher. Contains a pre key bundle if it's a session request.
  }

  // @required
  optional Type   type            = 1;
  optional string source          = 2;
  optional uint32 sourceDevice    = 7;
  optional string relay           = 3;
  // @required
  optional uint64 timestamp       = 5;
  optional bytes  legacyMessage   = 6; // Contains an encrypted DataMessage
  optional bytes  content         = 8; // Contains an encrypted Content
  // We may eventually want to make this required.
  optional string serverGuid      = 9;
  // We may eventually want to make this required.
  optional uint64 serverTimestamp = 10;
}

message TypingMessage {
    enum Action {
        STARTED = 0;
        STOPPED = 1;
    }

    // @required
    optional uint64 timestamp = 1;
    // @required
    optional Action action = 2;
    optional bytes groupId = 3;
}

message Content {
  optional DataMessage              dataMessage           = 1;
  optional SyncMessage              syncMessage           = 2;
  optional CallMessage              callMessage           = 3;
  optional NullMessage              nullMessage           = 4;
  optional ReceiptMessage           receiptMessage        = 5;
  optional TypingMessage            typingMessage         = 6;
  optional PrekeyBundleMessage      prekeyBundleMessage   = 101; // Loki
  optional LokiDeviceLinkMessage    lokiDeviceLinkMessage = 103; // Loki
}

message PrekeyBundleMessage { // Loki
  optional bytes  identityKey = 1;
  optional uint32 deviceID    = 2;
  optional uint32 prekeyID    = 3;
  optional uint32 signedKeyID = 4;
  optional bytes  prekey      = 5;
  optional bytes  signedKey   = 6;
  optional bytes  signature   = 7;
}

message LokiDeviceLinkMessage { // Loki
  optional string masterPublicKey = 1;
  optional string slavePublicKey  = 2;
  optional bytes  slaveSignature  = 3;
  optional bytes  masterSignature = 4;
}

message CallMessage {
  message Offer {
    // @required
    optional uint64 id = 1;
    // Signal-iOS renamed the description field to avoid
    // conflicts with [NSObject description].
    // @required
    optional string sessionDescription = 2;
  }

  message Answer {
    // @required
    optional uint64 id = 1;
    // Signal-iOS renamed the description field to avoid
    // conflicts with [NSObject description].
    // @required
    optional string sessionDescription = 2;
  }

  message IceUpdate {
    // @required
    optional uint64 id            = 1;
    // @required
    optional string sdpMid        = 2;
    // @required
    optional uint32 sdpMLineIndex = 3;
    // @required
    optional string sdp           = 4;
  }

  message Busy {
    // @required
    optional uint64 id = 1;
  }

  message Hangup {
    // @required
    optional uint64 id = 1;
  }

  optional Offer     offer     = 1;
  optional Answer    answer    = 2;
  repeated IceUpdate iceUpdate = 3;
  optional Hangup    hangup    = 4;
  optional Busy      busy      = 5;
  // Signal-iOS sends profile key with call messages
  // for earlier discovery
  optional bytes     profileKey = 6;
}

message ClosedGroupCiphertextMessageWrapper {
  // @required
  optional bytes ciphertext = 1;
  // @required
  optional bytes ephemeralPublicKey = 2;
}

message DataMessage {
  enum Flags {
    END_SESSION             = 1;
    EXPIRATION_TIMER_UPDATE = 2;
    PROFILE_KEY_UPDATE      = 4;
    UNLINK_DEVICE           = 128;
  }

  message Quote {
    message QuotedAttachment {
      enum Flags {
        VOICE_MESSAGE = 1;
      }

      optional string            contentType = 1;
      optional string            fileName    = 2;
      optional AttachmentPointer thumbnail   = 3;
      optional uint32            flags       = 4;
    }

    // @required
    optional uint64            id          = 1;
    // @required
    optional string            author      = 2;
    optional string            text        = 3;
    repeated QuotedAttachment  attachments = 4;
  }

  message Contact {
    message Name {
      optional string givenName   = 1;
      optional string familyName  = 2;
      optional string prefix      = 3;
      optional string suffix      = 4;
      optional string middleName  = 5;
      optional string displayName = 6;
    }

    message Phone {
      enum Type {
        HOME   = 1;
        MOBILE = 2;
        WORK   = 3;
        CUSTOM = 4;
      }

      optional string value = 1;
      optional Type   type  = 2;
      optional string label = 3;
    }

    message Email {
      enum Type {
        HOME   = 1;
        MOBILE = 2;
        WORK   = 3;
        CUSTOM = 4;
      }

      optional string value = 1;
      optional Type   type  = 2;
      optional string label = 3;
    }

    message PostalAddress {
      enum Type {
        HOME   = 1;
        WORK   = 2;
        CUSTOM = 3;
      }

      optional Type   type         = 1;
      optional string label        = 2;
      optional string street       = 3;
      optional string pobox        = 4;
      optional string neighborhood = 5;
      optional string city         = 6;
      optional string region       = 7;
      optional string postcode     = 8;
      optional string country      = 9;
    }

    message Avatar {
      optional AttachmentPointer avatar    = 1;
      optional bool              isProfile = 2;
    }

    optional Name              name            = 1;
    repeated Phone             number          = 3;
    repeated Email             email           = 4;
    repeated PostalAddress     address         = 5;
    optional Avatar            avatar          = 6;
    optional string            organization    = 7;
  }

  message Preview {
    // @required
    optional string            url   = 1;
    optional string            title = 2;
    optional AttachmentPointer image = 3;
  }

  message LokiProfile { // Loki
    optional string displayName = 1;
    optional string profilePicture = 2;
  }

  message ClosedGroupUpdate { // Loki
    enum Type {
      NEW                = 0; // groupPublicKey, name, groupPrivateKey, senderKeys, members, admins
      INFO               = 1; // groupPublicKey, name, senderKeys, members, admins
      SENDER_KEY_REQUEST = 2; // groupPublicKey
      SENDER_KEY         = 3; // groupPublicKey, senderKeys
    }

    message SenderKey {
      // @required
      optional bytes  chainKey  = 1;
      // @required
      optional uint32 keyIndex  = 2;
      // @required
      optional bytes  publicKey = 3;
    }

    optional string    name            = 1;
    // @required
    optional bytes     groupPublicKey  = 2;
    optional bytes     groupPrivateKey = 3;
    repeated SenderKey senderKeys      = 4;
    repeated bytes     members         = 5;
    repeated bytes     admins          = 6;
    // @required
    optional Type      type            = 7;
  }

  optional string            body              = 1;
  repeated AttachmentPointer attachments       = 2;
  optional GroupContext      group             = 3;
  optional uint32            flags             = 4;
  optional uint32            expireTimer       = 5;
  optional bytes             profileKey        = 6;
  optional uint64            timestamp         = 7;
  optional Quote             quote             = 8;
  repeated Contact           contact           = 9;
  repeated Preview           preview           = 10;
  optional LokiProfile       profile           = 101; // Loki: The current user's profile
  optional ClosedGroupUpdate closedGroupUpdate = 103; // Loki
  optional PublicChatInfo    publicChatInfo    = 999; // Loki: Internal public chat info
}

message NullMessage {
  optional bytes padding = 1;
}

message ReceiptMessage {
  enum Type {
    DELIVERY = 0;
    READ     = 1;
  }

  // @required
  optional Type   type      = 1;
  repeated uint64 timestamp = 2;
}

message Verified {
  enum State {
    DEFAULT    = 0;
    VERIFIED   = 1;
    UNVERIFIED = 2;
  }

  // @required
  optional string destination = 1;
  optional bytes  identityKey = 2;
  optional State  state       = 3;
  optional bytes  nullMessage = 4;
}

message SyncMessage {
  message Sent {
    message UnidentifiedDeliveryStatus {
      optional string destination  = 1;
      optional bool   unidentified = 2;
    }
    optional string                     destination              = 1;
    optional uint64                     timestamp                = 2;
    optional DataMessage                message                  = 3;
    optional uint64                     expirationStartTimestamp = 4;
    repeated UnidentifiedDeliveryStatus unidentifiedStatus       = 5;
    optional bool                       isRecipientUpdate        = 6 [default = false];
  }

  message Contacts {
    optional AttachmentPointer blob       = 1;
    // Signal-iOS renamed this property.
    optional bool              isComplete = 2 [default = false];
    optional bytes             data       = 101; // Loki
  }

  message Groups {
    optional AttachmentPointer blob = 1;
    optional bytes             data = 101; // Loki
  }

  message OpenGroupDetails { // Loki
    // @required
    optional string url       = 1;
    // @required
    optional uint64 channelID = 2;
  }

  message Blocked {
    repeated string numbers = 1;
    repeated bytes groupIds = 2;
  }

  message Request {
    enum Type {
      UNKNOWN       = 0;
      CONTACTS      = 1;
      GROUPS        = 2;
      BLOCKED       = 3;
      CONFIGURATION = 4;
    }

    // @required
    optional Type type = 1;
  }

  message Read {
    // @required
    optional string sender    = 1;
    // @required
    optional uint64 timestamp = 2;
  }

  message Configuration {
      optional bool readReceipts                   = 1;
      optional bool unidentifiedDeliveryIndicators = 2;
      optional bool typingIndicators               = 3;
      optional bool linkPreviews                   = 4;
  }

  optional Sent             sent          = 1;
  optional Contacts         contacts      = 2;
  optional Groups           groups        = 3;
  optional Request          request       = 4;
  repeated Read             read          = 5;
  optional Blocked          blocked       = 6;
  optional Verified         verified      = 7;
  optional Configuration    configuration = 9;
  optional bytes            padding       = 8;
  repeated OpenGroupDetails openGroups    = 100;
}

message AttachmentPointer {
  enum Flags {
    VOICE_MESSAGE = 1;
  }

  // @required
  optional fixed64 id          = 1;
  optional string  contentType = 2;
  optional bytes   key         = 3;
  optional uint32  size        = 4;
  optional bytes   thumbnail   = 5;
  optional bytes   digest      = 6;
  optional string  fileName    = 7;
  optional uint32  flags       = 8;
  optional uint32  width       = 9;
  optional uint32  height      = 10;
  optional string  caption     = 11;
  optional string  url         = 101; // Loki
}

message GroupContext {
  enum Type {
    UNKNOWN      = 0;
    UPDATE       = 1;
    DELIVER      = 2;
    QUIT         = 3;
    REQUEST_INFO = 4;
  }
  // @required
  optional bytes             id      = 1;
  // @required
  optional Type              type    = 2;
  optional string            name    = 3;
  repeated string            members = 4;
  optional AttachmentPointer avatar  = 5;
  repeated string            admins  = 6; // Loki
}

message ContactDetails {
  message Avatar {
    optional string contentType = 1;
    optional uint32 length      = 2;
  }

  // @required
  optional string   number      = 1;
  optional string   name        = 2;
  optional Avatar   avatar      = 3;
  optional string   color       = 4;
  optional Verified verified    = 5;
  optional bytes    profileKey  = 6;
  optional bool     blocked     = 7;
  optional uint32   expireTimer = 8;
  optional string   nickname    = 101; // Loki
}

message GroupDetails {
  message Avatar {
    optional string contentType = 1;
    optional uint32 length      = 2;
  }

  // @required
  optional bytes  id          = 1;
  optional string name        = 2;
  repeated string members     = 3;
  optional Avatar avatar      = 4;
  optional bool   active      = 5 [default = true];
  optional uint32 expireTimer = 6;
  optional string color       = 7;
  optional bool   blocked     = 8;
  repeated string admins      = 9; // Loki
}

// Internal - DO NOT SEND
message PublicChatInfo {
    optional uint64 serverID = 1;
}