Amarula.Protocol.Messages.MessageEncoder (amarula v0.2.2)
View SourceEncode an outgoing Proto.Message to the padded plaintext bytes that the
Signal cipher encrypts, ported from Baileys encodeWAMessage
(src/Utils/generics.ts):
encodeWAMessage(m) = writeRandomPadMax16(proto.Message.encode(m))writeRandomPadMax16 appends padLength bytes each equal to padLength,
where padLength = (rand_byte & 0x0f) + 1 (1..16). unpadRandomMax16 (the
receive side) reads the last byte as the pad length and strips it.
Summary
Functions
Build an album parent message announcing how many images/videos follow.
The children are sent afterwards, each referencing this message's key as their
album parent (see media/3's :album_parent opt).
Build a contact message from a display_name + vcard string. Pass a list of
{display_name, vcard} to build a contactsArrayMessage (multiple contacts).
Build a %Proto.ContextInfo{} from reply/mention opts, or nil when neither
is present (so a message stays a plain conversation/bare media)
Edit the message identified by target_key, replacing its body with new_text.
Sent to target_key.remoteJid with the edit="1" stanza attr (added by the
send path); the recipient replaces the original message's content.
Encode a %Proto.Message{} (or message map) and append random PKCS-style pad.
Build an event message. name is the event title. opts
Build a group-invite message — a sendable chat card that lets the recipient
join group_jid via code (from Amarula.Group.invite_code/2). opts:
:group_name, :caption, :expiration (unix ms when the code expires).
A PEER_DATA_OPERATION on-demand history request — sent to our own devices to ask
the phone for older messages of a chat (Baileys fetchMessageHistory). oldest_key
is the oldest message we already have; the phone replies with an ON_DEMAND
HistorySync notification carrying up to count older messages.
Convenience: media(:image, info, opts).
Keep (keep?: true, KEEP_FOR_ALL) or undo-keep (false, UNDO_KEEP_FOR_ALL)
the message identified by target_key — for messages in a disappearing chat.
Build a location message. lat/lng are floats (proto double). opts:
:name, :address, :url, :is_live.
Build a media message of type (:image/:video/:audio/:document/
:sticker) from an encrypt+upload result. info carries the uploaded
:url/:direct_path, the encrypt result (:media_key, :file_sha256,
:file_enc_sha256, :file_length) and :mimetype. opts adds per-type extras
(:caption, :width, :height, :seconds, :ptt, :file_name, :title).
Pin (pin?: true) or unpin (false) the message identified by target_key
for everyone in the chat (PIN_FOR_ALL / UNPIN_FOR_ALL).
A PEER_DATA_OPERATION placeholder-resend request for message_key — sent to our
own devices to ask the phone to re-deliver that message (Baileys
requestPlaceholderResend).
Build a poll-creation message. name is the question, options the choice
strings. opts
Build a pollUpdateMessage casting a vote on an existing poll. Args
Build a reaction to the message identified by target_key. emoji is the
reaction (e.g. "👍"); pass "" to REMOVE a previous reaction (Baileys semantics).
Build a delete-for-everyone (revoke) of the message identified by target_key.
Sent to target_key.remoteJid; the recipient replaces the message with a
"this message was deleted" tombstone.
Build a text message. With no :quoted/:mentions context it's a plain
conversation; when a reply or mentions are present WhatsApp requires an
extendedTextMessage (which carries the contextInfo), so we switch to that.
Functions
@spec album(non_neg_integer(), non_neg_integer()) :: Amarula.Protocol.Proto.Message.t()
Build an album parent message announcing how many images/videos follow.
The children are sent afterwards, each referencing this message's key as their
album parent (see media/3's :album_parent opt).
Build a contact message from a display_name + vcard string. Pass a list of
{display_name, vcard} to build a contactsArrayMessage (multiple contacts).
@spec context_info(keyword()) :: Amarula.Protocol.Proto.ContextInfo.t() | nil
Build a %Proto.ContextInfo{} from reply/mention opts, or nil when neither
is present (so a message stays a plain conversation/bare media):
:quoted— an%Amarula.Msg{}being replied to. FillsstanzaId(its id),participant(its sender jid), and inlines its raw proto asquotedMessage.:mentions— a list of jids or%Amarula.Address{}to tag (mentionedJid).
@spec edit(Amarula.Protocol.Proto.MessageKey.t(), String.t()) :: Amarula.Protocol.Proto.Message.t()
Edit the message identified by target_key, replacing its body with new_text.
Sent to target_key.remoteJid with the edit="1" stanza attr (added by the
send path); the recipient replaces the original message's content.
Encode a %Proto.Message{} (or message map) and append random PKCS-style pad.
Build an event message. name is the event title. opts:
:description— free text.:location—{lat, lng}floats, or a keyword with:name/:address.:join_link— a call/meeting URL.:start_time/:end_time— unix seconds.:extra_guests_allowed— boolean.
Build a group-invite message — a sendable chat card that lets the recipient
join group_jid via code (from Amarula.Group.invite_code/2). opts:
:group_name, :caption, :expiration (unix ms when the code expires).
@spec history_sync_on_demand_request( Amarula.Protocol.Proto.MessageKey.t(), integer(), non_neg_integer() ) :: Amarula.Protocol.Proto.Message.t()
A PEER_DATA_OPERATION on-demand history request — sent to our own devices to ask
the phone for older messages of a chat (Baileys fetchMessageHistory). oldest_key
is the oldest message we already have; the phone replies with an ON_DEMAND
HistorySync notification carrying up to count older messages.
Convenience: media(:image, info, opts).
@spec keep(Amarula.Protocol.Proto.MessageKey.t(), boolean()) :: Amarula.Protocol.Proto.Message.t()
Keep (keep?: true, KEEP_FOR_ALL) or undo-keep (false, UNDO_KEEP_FOR_ALL)
the message identified by target_key — for messages in a disappearing chat.
Build a location message. lat/lng are floats (proto double). opts:
:name, :address, :url, :is_live.
@spec media(:image | :video | :audio | :document | :sticker, map(), keyword()) :: Amarula.Protocol.Proto.Message.t()
Build a media message of type (:image/:video/:audio/:document/
:sticker) from an encrypt+upload result. info carries the uploaded
:url/:direct_path, the encrypt result (:media_key, :file_sha256,
:file_enc_sha256, :file_length) and :mimetype. opts adds per-type extras
(:caption, :width, :height, :seconds, :ptt, :file_name, :title).
@spec pin(Amarula.Protocol.Proto.MessageKey.t(), boolean()) :: Amarula.Protocol.Proto.Message.t()
Pin (pin?: true) or unpin (false) the message identified by target_key
for everyone in the chat (PIN_FOR_ALL / UNPIN_FOR_ALL).
@spec placeholder_resend_request(Amarula.Protocol.Proto.MessageKey.t()) ::
Amarula.Protocol.Proto.Message.t()
A PEER_DATA_OPERATION placeholder-resend request for message_key — sent to our
own devices to ask the phone to re-deliver that message (Baileys
requestPlaceholderResend).
@spec poll(String.t(), [String.t(), ...], keyword()) :: {Amarula.Protocol.Proto.Message.t(), binary()}
Build a poll-creation message. name is the question, options the choice
strings. opts:
:selectable— max selectable options (0 = unlimited; default 1 = single).:announcement— community-announcement-group poll (v2).:message_secret— 32-byte vote-encryption key (default: random). Keep it; tallying incoming votes needs it (Poll.tally/3).
Picks the proto variant like Baileys: v2 for announcement, v3 for single-select,
v1 for multi. Returns {message, message_secret}.
@spec poll_vote( Amarula.Protocol.Proto.MessageKey.t(), String.t(), String.t(), binary(), [String.t()] ) :: Amarula.Protocol.Proto.Message.t()
Build a pollUpdateMessage casting a vote on an existing poll. Args:
poll_key— the%Proto.MessageKey{}of the poll-creation message.creator_jid— the poll creator's jid (the poll message author).voter_jid— our jid (the vote is encrypted per voter).message_secret— the poll's 32-byte secret (returned bypoll/3at creation, or decoded from the poll'smessageContextInfo).option_names— the chosen option strings (must match the poll's options).
The vote is AES-256-GCM encrypted under the poll secret (PollCrypto), so it
round-trips through the same decrypt path tallies use.
@spec reaction(Amarula.Protocol.Proto.MessageKey.t(), String.t()) :: Amarula.Protocol.Proto.Message.t()
Build a reaction to the message identified by target_key. emoji is the
reaction (e.g. "👍"); pass "" to REMOVE a previous reaction (Baileys semantics).
@spec revoke(Amarula.Protocol.Proto.MessageKey.t()) ::
Amarula.Protocol.Proto.Message.t()
Build a delete-for-everyone (revoke) of the message identified by target_key.
Sent to target_key.remoteJid; the recipient replaces the message with a
"this message was deleted" tombstone.
Build a text message. With no :quoted/:mentions context it's a plain
conversation; when a reply or mentions are present WhatsApp requires an
extendedTextMessage (which carries the contextInfo), so we switch to that.