Imessages



Messages in iOS 5

Use Messages for web to send SMS, MMS and chat messages from your computer. Open the Messages app on your Android phone to get started. If this is on Xbox one or the App, check out this article here: Why can’t I send messages from my Xbox One or the Xbox app? Help users express themselves in richer ways, create and share content, play games, make payments, and more — without ever leaving their conversations. Learn how to prepare, build, and submit apps for the App Store for iMessage. And businesses can connect with customers directly within Messages for customer support and commerce.

Messages is the built-in system application to send messages. Initially (in earlier iOS versions) this was only for sending and receiving SMS (text) messages. Support for sending and receiving MMS messages was introduced in iOS 3.0, while support for sending and receiving iMessages was introduced in iOS 5. The application itself is located in /Applications/MobileSMS.app/.

  • 3Serialization
  • 4Tables

iMessage

With iOS 5 Apple introduced the iCloud based instant messaging service, iMessage, which works across different iOS devices and Mac OS X, and is the first native messaging service for iPod touch and iPad. Messages for Mac OS X was introduced with OS X Mountain Lion, and replaced the iChat instant messaging program.

Activation

iMessages on iOS is activated in the same way as FaceTime, with a silent SMS being sent to a carrier defined number and a successful registration SMS being returned. This 'verifies' the phone number for sending and receiving iMessages. Email (AppleID) verification does not use silent SMS, and only sends an email containing a verification link. This is the only method for iMessages on the iPad, iPod touch and Mac OS X.

iMessage is deeply integrated and built around Apple's Push Notification Server over port 5223.

Serialization

To backup or restore the data of this application without iTunes, the following information might be useful. Initial data for this analysis comes from an iPhone 3GS with firmware 3.1.3, which was later restored / upgraded to an iPhone 4 and finally to an iPhone 4S with iOS 5.0.1. On lower or higher firmware versions there are differences in the data.

In the folder /var/mobile/Library/SMS/ there are the following files:

  • sms.db
  • sms.db-shm
  • sms.db-wal
  • sms-legacy.db
  • folder Attachments
  • folder Drafts
  • folder Parts

The files sms.db-shm and sms.db-wal are probably used for indexing or search and can be recreated if deleted (?). If the database is updated manually, it's important to recreate these files. On a jailbroken device, they could be recreated using the sqlite3 program, for example by issuing the following command: sqlite3 sms.db .dump>/dev/null.
The sms-legacy.db file was not on my iPhone, but another user claimed to have this file (see jbqa reference).
The iTunes Backup filename of sms.db is 3d0d7e5fb2ce288813306e4d4636395e047a3d28.

The Attachments folder contains subfolders and files, which are referenced in the main database file in the table madrid_attachment (see there).

Drafts

In the folder Drafts there is a file PENDING-recipients.plist (if there is a pending draft with already recipients added) and the content is a plist with an array of strings with the recipients (phone numbers). There is also a subfolder PENDING.draft with a file message.plist containing a dict with the following three values:

Imessages
  • markupString: The text in HTML format (HTML encoded) that has been entered already
  • resources: array of dict for every image:
    • duration (integer): 0 for images, number of seconds (duration) for videos
    • exportedFilename: (filename, without path, ending in .jpg, .png or .3gp)
    • mimeType: image/jpeg or image/png or video/x-internal-iphone
  • textString: The text that has been entered already (white spaces and line breaks retained)

Images are put into the markupString like this:

n is the image number, starting with 0. The width varies slightly, depending on the image width/height ratio, but the height is always 110px (90px for videos). The images theirself are stored in the same folder with corresponding names like data-0, data-1, etc.

In case of a video, the data file is not the video itself, but a bplist with this content (dict): Microsoft office 2008 for mac torrent.

  • CKSMSComposeOptionFilenameKey (string): /var/tmp/capture/capturedvideo.MOV or /var/tmp/capture-T0x11d520.tmp.OEBOK7/capturedvideo.MOV (or similar)
  • CKSMSComposeOptionPreviewImageDataKey (data): big blob (base64 encoded)

For the blob, this was in my test only 5510 byte long, so it's not the movie itself. The only strings in the blob were 'JFIF' and 'Exif' somewhere near the beginning, so it can be assumed this is metadata or the screenshot shown in the message bubble.

Main database file

So we're just looking at the file sms.db, this is an SQLite database with the following tables in it:

  • sqlite_master
  • _SqliteDatabaseProperties
  • msg_group
  • group_member
  • message
  • msg_pieces
  • madrid_attachment
  • madrid_chat

Indexes

The following indexes are defined:

index nametable namefield name(s)
sqlite_autoindex__SqliteDatabaseProperties_1_SqliteDatabaseProperties
message_group_indexmessagegroup_id, ROWID
message_flags_indexmessageflags
pieces_message_indexmsg_piecesmessage_id
madrid_attachment_message_indexmadrid_attachmentmessage_id
madrid_attachment_guid_indexmadrid_attachmentattachment_guid
madrid_attachment_filename_indexmadrid_attachmentfilename
madrid_guid_indexmessagemadrid_guid
group_id_indexgroup_membergroup_id
madrid_chat_style_indexmadrid_chatstyle
madrid_chat_state_indexmadrid_chatstate
madrid_chat_account_id_indexmadrid_chataccount_id
madrid_chat_chat_identifier_indexmadrid_chatchat_identifier
madrid_chat_service_name_indexmadrid_chatservice_name
madrid_chat_guid_indexmadrid_chatguid
madrid_chat_room_name_indexmadrid_chatroom_name
madrid_chat_account_login_indexmadrid_chataccount_login
madrid_roomname_service_indexmessagemadrid_roomname, madrid_service
madrid_handle_service_indexmessagemadrid_handle, madrid_service

Triggers

The following triggers are defined:

trigger namecriteria 1criteria 2action
insert_unread_message
mark_message_unread
mark_message_read
delete_message
insert_newest_message
delete_newest_message
delete_pieces-

All defined triggers act on the table message, therefore this is not mentioned in this list with a separate column.

From the trigger statements it is visible that there must be a function called read(x) which is used on the field message.flags. As SQLite does not have this function, but is open-sourced, this has probably been added into the code to facilitate handling the read-flag of a message. Please note that there is also a column called 'read'.

Please note that all date values are stored as a number which means the number of seconds since 1 Jan 2001.

The word 'madrid' was the codename for iMessage, before this was a product name (according to pytey, see reference).

Tables

sqlite_master

This table is contained in every SQLite database and contains general information about the content. Parallels desktop 12 for mac retail box cis. It has these fields:

field namedescription
typeeither 'table' or 'index' or 'trigger'
namename of the table or index or trigger
tbl_namesame as name for table, related table name for index and trigger
rootpageinteger, internal id where to find the data (?), or 0 for trigger
sqlcreation statement

This is the content of this table:

typenametbl_namerootpagesql
table_SqliteDatabaseProperties_SqliteDatabaseProperties3CREATE TABLE _SqliteDatabaseProperties (key TEXT, value TEXT, UNIQUE(key))
tablemessagemessage5CREATE TABLE message (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT, date INTEGER, text TEXT, flags INTEGER, replace INTEGER, svc_center TEXT, group_id INTEGER, association_id INTEGER, height INTEGER, UIFlags INTEGER, version INTEGER, subject TEXT, country TEXT, headers BLOB, recipients BLOB, read INTEGER, madrid_attributedBody BLOB, madrid_handle TEXT, madrid_version INTEGER, madrid_guid TEXT, madrid_type INTEGER, madrid_roomname TEXT, madrid_service TEXT, madrid_account TEXT, madrid_flags INTEGER, madrid_attachmentInfo BLOB, madrid_url TEXT, madrid_error INTEGER, is_madrid INTEGER, madrid_date_read INTEGER, madrid_date_delivered INTEGER, madrid_account_guid TEXT)
tablesqlite_sequencesqlite_sequence6CREATE TABLE sqlite_sequence(name,seq)
tablemsg_groupmsg_group7CREATE TABLE msg_group (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, type INTEGER, newest_message INTEGER, unread_count INTEGER, hash INTEGER)
tablegroup_membergroup_member8CREATE TABLE group_member (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER, address TEXT, country TEXT)
tablemsg_piecesmsg_pieces9CREATE TABLE msg_pieces (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, message_id INTEGER, data BLOB, part_id INTEGER, preview_part INTEGER, content_type TEXT, height INTEGER, version INTEGER, flags INTEGER, content_id TEXT, content_loc TEXT, headers BLOB)
tablemadrid_attachmentmadrid_attachment13CREATE TABLE madrid_attachment (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, attachment_guid TEXT, created_date INTEGER, start_date INTEGER, filename TEXT, uti_type TEXT, mime_type TEXT, transfer_state INTEGER, is_incoming INTEGER, message_id INTEGER)
tablemadrid_chatmadrid_chat25CREATE TABLE madrid_chat (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, style INTEGER, state INTEGER, account_id TEXT, properties BLOB, chat_identifier TEXT, service_name TEXT, guid TEXT, room_name TEXT, account_login TEXT, participants BLOB)
triggerinsert_unread_messagemessage0CREATE TRIGGER insert_unread_message AFTER INSERT ON message WHEN NOT read(new.flags) BEGIN UPDATE msg_group SET unread_count = (SELECT unread_count FROM msg_group WHERE ROWID = new.group_id) + 1 WHERE ROWID = new.group_id; END
triggermark_message_unreadmessage0CREATE TRIGGER mark_message_unread AFTER UPDATE ON message WHEN read(old.flags) AND NOT read(new.flags) BEGIN UPDATE msg_group SET unread_count = (SELECT unread_count FROM msg_group WHERE ROWID = new.group_id) + 1 WHERE ROWID = new.group_id; END
triggermark_message_readmessage0CREATE TRIGGER mark_message_read AFTER UPDATE ON message WHEN NOT read(old.flags) AND read(new.flags) BEGIN UPDATE msg_group SET unread_count = (SELECT unread_count FROM msg_group WHERE ROWID = new.group_id) - 1 WHERE ROWID = new.group_id; END
triggerdelete_messagemessage0CREATE TRIGGER delete_message AFTER DELETE ON message WHEN NOT read(old.flags) BEGIN UPDATE msg_group SET unread_count = (SELECT unread_count FROM msg_group WHERE ROWID = old.group_id) - 1 WHERE ROWID = old.group_id; END
triggerinsert_newest_messagemessage0CREATE TRIGGER insert_newest_message AFTER INSERT ON message WHEN new.ROWID >= IFNULL((SELECT MAX(ROWID) FROM message WHERE message.group_id = new.group_id), 0) BEGIN UPDATE msg_group SET newest_message = new.ROWID WHERE ROWID = new.group_id; END
triggerdelete_newest_messagemessage0CREATE TRIGGER delete_newest_message AFTER DELETE ON message WHEN old.ROWID = (SELECT newest_message FROM msg_group WHERE ROWID = old.group_id) BEGIN UPDATE msg_group SET newest_message = (SELECT ROWID FROM message WHERE group_id = old.group_id AND ROWID = (SELECT max(ROWID) FROM message WHERE group_id = old.group_id)) WHERE ROWID = old.group_id; END
triggerdelete_piecesmessage0CREATE TRIGGER delete_pieces AFTER DELETE ON message BEGIN DELETE from msg_pieces where old.ROWID msg_pieces.message_id; END
indexsqlite_autoindex__SqliteDatabaseProperties_1_SqliteDatabaseProperties4NULL
indexmessage_group_indexmessage10CREATE INDEX message_group_index ON message(group_id, ROWID)
indexmessage_flags_indexmessage11CREATE INDEX message_flags_index ON message(flags)
indexpieces_message_indexmsg_pieces12CREATE INDEX pieces_message_index ON msg_pieces(message_id)
indexmadrid_attachment_message_indexmadrid_attachment14CREATE INDEX madrid_attachment_message_index ON madrid_attachment(message_id)
indexmadrid_attachment_guid_indexmadrid_attachment15CREATE INDEX madrid_attachment_guid_index ON madrid_attachment(attachment_guid)
indexmadrid_attachment_filename_indexmadrid_attachment16CREATE INDEX madrid_attachment_filename_index ON madrid_attachment(filename)
indexmadrid_guid_indexmessage18CREATE INDEX madrid_guid_index ON message(madrid_guid)
indexgroup_id_indexgroup_member24CREATE INDEX group_id_index ON group_member(group_id)
indexmadrid_chat_style_indexmadrid_chat26CREATE INDEX madrid_chat_style_index ON madrid_chat(style)
indexmadrid_chat_state_indexmadrid_chat27CREATE INDEX madrid_chat_state_index ON madrid_chat(state)
indexmadrid_chat_account_id_indexmadrid_chat23CREATE INDEX madrid_chat_account_id_index ON madrid_chat(account_id)
indexmadrid_chat_chat_identifier_indexmadrid_chat22CREATE INDEX madrid_chat_chat_identifier_index ON madrid_chat(chat_identifier)
indexmadrid_chat_service_name_indexmadrid_chat21CREATE INDEX madrid_chat_service_name_index ON madrid_chat(service_name)
indexmadrid_chat_guid_indexmadrid_chat20CREATE INDEX madrid_chat_guid_index ON madrid_chat(guid)
indexmadrid_chat_room_name_indexmadrid_chat19CREATE INDEX madrid_chat_room_name_index ON madrid_chat(room_name)
indexmadrid_chat_account_login_indexmadrid_chat17CREATE INDEX madrid_chat_account_login_index ON madrid_chat(account_login)
indexmadrid_roomname_service_indexmessage28CREATE INDEX madrid_roomname_service_index ON message(madrid_roomname, madrid_service)
indexmadrid_handle_service_indexmessage29CREATE INDEX madrid_handle_service_index ON message(madrid_handle, madrid_service)

Please note that the values for rootpage might differ in every database.

_SqliteDatabaseProperties

This seems to be a general-purpose table to store some configuration values.

field nametype
keyTEXT
valueTEXT
UNIQUE(key)

These values are stored in the table:

keyvaluedescription
counter_last_reset0?
_UniqueIdentifier960B6637-167E-44A1-86E5-90E3DFE768AC?
_ClientVersion21?
counter_out_all254counts the number of outgoing messages (since last counter reset)
counter_out_lifetime254counts the number of outgoing messages (since forever, isn't affected by an counter reset)
counter_in_all468counts the number of incoming messages (since last counter reset)
counter_in_lifetime468counts the number of incoming messages (since forever, isn't affected by an counter reset)
__CPRecordSequenceNumber2835?

message

This is the main table where all messages are stored:

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
addressTEXTNULL or a name or a phone number (with or without spaces) of the other person (sent to or received from)
dateINTEGERmessage date
textTEXTmessage content
flagsINTEGERunknown, possible values: 0, 2, 3, 5, 35, 16387. Probably a bit-set. The value 35 was set in a SMS that couldn't get sent out and is stil marked with a red exclamation mark letting you send it again.
replaceINTEGERunknown, possible values: 0, 1, 2
svc_centerTEXTNULL
group_idINTEGER0 or foreign key to msg_group.ROWID
association_idINTEGERoften 0, but sometimes a copy of the date field
heightINTEGERalways 0
UIFlagsINTEGERunknown, possible values: 0, 4, 5, 6, 7
versionINTEGERalways 0
subjectTEXTThe subject of an iMessage/MMS-message, or NULL if it's an SMS or if subject is not used on a iMessage/MMS-message
countryTEXTNULL or an ISO country code (eg: 'ch' for Switzerland)
headersBLOBalways NULL
recipientsBLOBnormally NULL, one entry had an xml value in it
readINTEGER0 or 1 (Assume 0 = unread and 1 is read though Madrid messages are always 0 so it probably doesn't apply to them)
madrid_attributedBodyBLOBblob, content unknown. The only strings in it are 'JFIF' and 'Exif', so this is probably meta-data.
madrid_handleTEXTNULL if not an iMessage or a phone number of the other person (sender or receiver)
madrid_versionINTEGERNULL if pre-iOS 5.0 or 0
madrid_guidTEXTGUID (unique to the message) or NULL if not an iMessage
madrid_typeINTEGER0 or NULL if pre-iOS 5.0
madrid_roomnameTEXTNULL
madrid_serviceTEXT'Madrid' or NULL if not an iMessage
madrid_accountTEXTNULL if not an iMessage or 'p:' & own phone number or 'e:' & email registered for iMessage
madrid_flagsINTEGERmessage type. Known values: NULL (if not an iMessage), 12289 (received), 32773 (send error), 36869 (sent), 45061 (sent), 77825 (received message containing parsed data eg: phone, email, website), 102405 (sent message containing parsed data eg: phone, email, website)
madrid_attachmentInfoBLOBNULL or blob. The blob contains these strings: streamtyped, NSMutableArray, NSArray, NSObject, NSMutableString, NSString, and a GUID. Format unknown.
madrid_urlTEXTalways an empty string
madrid_errorINTEGERempty string if message is pre-iOS 5.0 or 0 if after
is_madridINTEGERspecifies if it's an iMessage or not, value 0 or 1 (0=SMS/MMS, 1=iMessage)
madrid_date_readINTEGERnull if message is pre-iOS 5.0, 0 if sms or a sent iMessage, integer value representing the date read
madrid_date_deliveredINTEGERnull if message is pre-iOS 5.0, 0 if sms or a received iMessage, integer value representing the date sent
madrid_account_guidTEXTGUID of account used (multiple entries may be found representing either the phone or email registered with iMessage) or empty if not an iMessage

sqlite_sequence

This table does not define data types. This is the data in the table:

nameseq
msg_group71
message784
group_member71
msg_pieces3
madrid_chat3
madrid_attachment3

msg_group

This defines a chat (SMS/text/message) conversation group.

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
typeINTEGER0 if only one recipient, 1 if multiple recipients
newest_messageINTEGERforeign key to message. This value is auto-updated by triggers when inserting / deleting a message, so that this always points to the newest message.
unread_countINTEGERThe number of unread messages in this group. This value is auto-incremented/decremented by triggers when inserting or deleting an unread message or when marking a message as read or unread.
hashINTEGERsigned 32-bit integer value (calculation?)

group_member

This defines the member of the chat (SMS/text/message) conversation group. As you currently cannot define groups, there is always only one member in each group, so the group_id and ROWID values match.

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
group_idINTEGERforeign key to msg_group.ROWID
addressTEXTname or phone number (with or without spaces)
countryTEXTISO country code eg: 'ch' for Switzerland

msg_pieces

This table contains information about MMS objects. (?)

When a message is deleted, a trigger checks if there are related entries in this table here and deletes them also.

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
message_idINTEGERforeign key to message
dataBLOBNULL
part_idINTEGER0
preview_partINTEGER0 or -1
content_typeTEXTempty string or 'image/jpeg'
heightINTEGER0
versionINTEGER1
flagsINTEGER0
content_idTEXTNULL or 1
content_locTEXTimage file name without path (like 'IMG_0104.JPG')
headersBLOBNULL

madrid_attachment

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
attachment_guidTEXTGUID - this matches the subfolder name in the folder Attachments
created_dateINTEGERunsigned integer value with the creation date
start_dateINTEGER0
filenameTEXTcomplete filename (with path)
uti_typeTEXT'public.jpeg' or 'public.vcard'
mime_typeTEXT'image/jpeg' or 'text/vcard'
transfer_stateINTEGER5
is_incomingINTEGER0
message_idINTEGER-1

madrid_chat

What is the best printer scanner for a mac. In my case there are three entries in this table.

field nametypevalue / description
ROWIDINTEGER PRIMARY KEY AUTOINCREMENTprimary key
styleINTEGEROnly known value is 45
stateINTEGEROnly known value is 3
account_idTEXTGUID of the iMessage account you used
propertiesBLOBNULL for the second row or a bplist (see below)
chat_identifierTEXTphone number of the other person in international format, no spaces
service_nameTEXT'Madrid'
guidTEXTsame as chat_identifier, but with a '-' in front of it
room_nameTEXTNULL
account_loginTEXT'P:' & own phone number or 'E:' & email registered for iMessage
participantsBLOBbplist (see below)

For the properties bplist this contains the following settings for the first row (dict):

  • CKMadridServiceConsecutiveCanceledMessageCount (integer) = 2
  • CKMadridServiceLastCanceledMessageTime (real) = date/time value

or this for the third row (dict):

  • CKPlaceholderTimeSince1970Property (real) = date/time value
Imessages

Please note that the date/time values here are the number of seconds since 1 Jan 1970 and not since 2001 like in the other database fields. There are also fractions of a second (up to seven digits).

For the participants bplist, in all three rows there is the same content (array):

  • (string): a phone number, not my own, in international format, no spaces

The interesting thing is that the phone number of the participants list matches the phone number of the first row. The people in the second and third row don't know the person from the participants list. Probably this is garbage in this table or its implementation is not finished yet. I also don't have any related messages.

The field chat_identifier seems to be unique. This table is probably an index of iMessage contacts.

References

  • Apple's description of iMessage (broken) (Archive.org's archive of page)
  • script to merge two SMS databases.
Retrieved from 'https://www.theiphonewiki.com/w/index.php?title=Messages&oldid=48858'

Here's how it works

Messages in iCloud are updated automatically, so you always have the same view everywhere you use iMessage. When you delete a message, photo, or conversation on one device, it’s removed from all of your devices. And since all of your attachments are stored in iCloud, you can save space on your device.

You can use Messages in iCloud on your iPhone, iPad, iPod touch, Apple Watch, and Mac. For your privacy, Messages in iCloud is end-to-end encrypted,* which means you can't view or access Messages online via browser.

* Learn more about iCloud security.

Turn on Messages in iCloud

To turn on Messages in iCloud, make sure that you've set up iCloud and are signed in with the same Apple ID on all your devices. You also need to use two-factor authentication with your Apple ID, and turn on iCloud Keychain.

On your iPhone, iPad, or iPod touch

  1. Go to Settings.
  2. Tap [your name].
  3. Tap iCloud.
  4. Turn on Messages.

On your Mac

  1. Open Messages.
  2. In the menu bar, choose Messages > Preferences.
  3. Click iMessage.
  4. Select the checkbox next to Enable Messages in iCloud.

Turn off Messages in iCloud

When you turn off Messages on your iPhone, iPad, iPod touch, or Mac, you can choose to turn off Messages in iCloud for just that device or all of your devices. Any device where Messages in iCloud is still turned on continues to store what you send and receive from that device in iCloud.

On your iPhone, iPad, or iPod touch

Imessages On Pc

  1. Go to Settings.
  2. Tap [your name] > iCloud.
  3. Turn off Messages.

On your Mac

  1. Open Messages.
  2. In the menu bar, choose Messages > Preferences.
  3. Click iMessage.
  4. Deselect the checkbox next to Enable Messages in iCloud.

If you turn off Messages in iCloud on an iPhone, iPad, or iPod touch your message history will be included in a separate iCloud backup. If you set up an Apple Watch for a family member, Messages in iCloud is the only way to back up messages.

Imessages Waiting For Activation

Make the most of Messages

Message+ App

  • Learn how to use Messages on your iPhone, iPad, or iPod touch.
  • Personalize your messages with Digital Touch, iMessage apps, and message effects.
  • Send photos, videos, or audio messages and group messages.
  • Learn how to use Messages on your Mac.