Messages

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.

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  there are the following files: The files  and   are probably used for indexing or search and can be recreated if deleted (?). The legacy file was not on my iPhone, but another user claimed to have this file (see jbqa reference).
 * folder
 * folder
 * folder
 * folder
 * folder
 * folder
 * folder

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

Drafts
In the folder  there is a file   (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  with a file   containing a dict with the following three values: 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,  , etc.
 * 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)

In case of a video, the data file is not the video itself, but a bplist with this content (dict): 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.
 * CKSMSComposeOptionFilenameKey (string): /var/tmp/capture/capturedvideo.MOV or /var/tmp/capture-T0x11d520.tmp.OEBOK7/capturedvideo.MOV (or similar)
 * CKSMSComposeOptionPreviewImageDataKey (data): big blob (base64 encoded)

Main database file
So we're just looking at the file, 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:

Triggers
The following triggers are defined: 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).

sqlite_master
This table is contained in every SQLite database and contains general information about the content. It has these fields:

This is the content of this table: 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.

These values are stored in the table:

message
This is the main table where all messages are stored:

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

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

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.

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.

madrid_chat
In my case there are three entries in this table.

For the properties bplist this contains the following settings for the first row (dict): or this for the third row (dict): 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).
 * CKMadridServiceConsecutiveCanceledMessageCount (integer) = 2
 * CKMadridServiceLastCanceledMessageTime (real) = date/time value
 * CKPlaceholderTimeSince1970Property (real) = date/time value

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.