2 /// \file protostructs.h
3 /// USB Blackberry bulk protocol API. This is split out from
4 /// protocol.h so that low level, packed structs can be
5 /// compiled separately from the application. This prevents
6 /// aliasing problems in the application, or using
7 /// -fno-strict-aliasing, which the library only needs.
9 /// Do not include this in any Barry library header.
10 /// This may only be included from .cc files, in order
11 /// to hide aliasing concernes from the application.
15 Copyright (C) 2005-2008, Net Direct Inc. (http://www.netdirect.ca/)
17 This program is free software; you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 2 of the License, or
20 (at your option) any later version.
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26 See the GNU General Public License in the COPYING file at the
27 root directory of this project for more details.
30 #ifndef __BARRY_PROTOSTRUCTS_H__
31 #define __BARRY_PROTOSTRUCTS_H__
34 #include <sys/types.h>
36 // forward declarations
37 namespace Barry
{ class Data
; }
39 namespace Barry
{ namespace Protocol
{
41 ///////////////////////////////////////////////////////////////////////////////
46 } __attribute__ ((packed
));
49 ///////////////////////////////////////////////////////////////////////////////
50 // Record sub-field structs
52 struct GroupLink
// used for Contacts records
56 } __attribute__ ((packed
));
58 struct MessageAddress
// used for Message records
61 uint8_t addr
[1]; // 2 null terminated strings: first
62 // contains full name, second contains
64 } __attribute__ ((packed
));
68 ///////////////////////////////////////////////////////////////////////////////
69 // Record Field Formats
73 uint16_t size
; // including null terminator
87 } __attribute__ ((packed
)) u
;
89 } __attribute__ ((packed
));
90 #define COMMON_FIELD_HEADER_SIZE (sizeof(Barry::Protocol::CommonField) - sizeof(Barry::Protocol::CommonField::CommonFieldData))
91 #define COMMON_FIELD_MIN1900_SIZE (sizeof(int32_t))
93 struct CommandTableField
95 uint8_t size
; // no null terminator
98 } __attribute__ ((packed
));
99 #define COMMAND_FIELD_HEADER_SIZE (sizeof(Barry::Protocol::CommandTableField) - 1)
105 uint32_t dbSize
; // assumed from Cassis docs...
107 uint16_t dbRecordCount
;
109 uint16_t nameSize
; // includes null terminator
111 } __attribute__ ((packed
));
112 #define OLD_DBDB_FIELD_HEADER_SIZE (sizeof(Barry::Protocol::OldDBDBField) - 1)
118 uint32_t dbSize
; // assumed from Cassis docs...
120 uint32_t dbRecordCount
;
122 uint16_t nameSize
; // includes null terminator
124 uint8_t name
[1]; // followed by 2 zeros!
125 uint16_t unknown
; // this comes after the
126 // null terminated name, but
127 // is here for size calcs
128 } __attribute__ ((packed
));
129 #define DBDB_FIELD_HEADER_SIZE (sizeof(Barry::Protocol::DBDBField) - 1)
131 struct RecordStateTableField
133 uint8_t rectype
; // it is unknown exactly what
134 // this field does, but it
135 // shows up here and in the
136 // tagged record header, and
137 // for some of the records
138 // they must match when writing
140 uint32_t uniqueId
; // matches the uniqueId of say,
141 // address book records
142 uint8_t flags
; // bit 0x01 is the dirty flag
143 // don't know if any other bits
145 #define BARRY_RSTF_DIRTY 0x01
147 } __attribute__ ((packed
));
149 struct CalendarRecurrenceDataField
// as documented in the Cassis project spec
152 #define CRDF_TYPE_DAY 0x01
153 #define CRDF_TYPE_MONTH_BY_DATE 0x03
154 #define CRDF_TYPE_MONTH_BY_DAY 0x04
155 #define CRDF_TYPE_YEAR_BY_DATE 0x05
156 #define CRDF_TYPE_YEAR_BY_DAY 0x06
157 #define CRDF_TYPE_WEEK 0x0c
159 uint8_t unknown
; // always 0x01
162 uint32_t endTime
; // 0xFFFFFFFF for never
166 // Note: blank fields should be set to 0
170 uint8_t day
[6]; // always zeros!
171 } __attribute__ ((packed
)) day
;
175 uint8_t monthDay
; // day of month to recur on
178 } __attribute__ ((packed
)) month_by_date
;
182 uint8_t weekDay
; // day of week to recur on (0-6)
183 uint8_t week
; // week of month to recur on
184 // (1 to 5, first week, second
187 } __attribute__ ((packed
)) month_by_day
;
191 uint8_t monthDay
; // day of month to recur on
194 uint8_t month
; // month to recur on (1-12)
196 } __attribute__ ((packed
)) year_by_date
;
200 uint8_t weekDay
; // day of week to recur on (0-6)
201 uint8_t week
; // week of month (1 to 5)
202 uint8_t month
; // (1-12)
204 } __attribute__ ((packed
)) year_by_day
;
208 uint8_t days
; // bitmask
209 #define CRDF_WD_SUN 0x01
210 #define CRDF_WD_MON 0x02
211 #define CRDF_WD_TUE 0x04
212 #define CRDF_WD_WED 0x08
213 #define CRDF_WD_THU 0x10
214 #define CRDF_WD_FRI 0x20
215 #define CRDF_WD_SAT 0x40
218 } __attribute__ ((packed
)) week
;
220 } __attribute__ ((packed
)) u
;
222 } __attribute__ ((packed
));
223 #define CALENDAR_RECURRENCE_DATA_FIELD_SIZE sizeof(Barry::Protocol::CalendarRecurrenceDataField)
227 ///////////////////////////////////////////////////////////////////////////////
228 // Packed field structures - odd format used with Service Book records
230 struct PackedField_02
236 } __attribute__ ((packed
));
237 #define PACKED_FIELD_02_HEADER_SIZE (sizeof(Barry::Protocol::PackedField_02) - 1)
239 struct PackedField_10
244 } __attribute__ ((packed
));
245 #define PACKED_FIELD_10_HEADER_SIZE (sizeof(Barry::Protocol::PackedField_10) - 1)
250 ///////////////////////////////////////////////////////////////////////////////
251 // Service Book field and record structures
253 struct ServiceBookConfigField
257 } __attribute__ ((packed
));
258 #define SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE (sizeof(Barry::Protocol::ServiceBookConfigField) - 1)
261 ///////////////////////////////////////////////////////////////////////////////
262 // DB Command Parameter structures
266 uint16_t recordIndex
; // index comes from RecordStateTable
268 } __attribute__ ((packed
));
269 #define DBC_RECORD_HEADER_SIZE (sizeof(Barry::Protocol::DBC_Record) - 1)
271 struct DBC_RecordFlags
276 } __attribute__ ((packed
));
277 #define DBC_RECORD_FLAGS_SIZE (sizeof(Barry::Protocol::DBC_RecordFlags))
279 struct DBC_TaggedUpload
281 uint8_t rectype
; // it is unknown exactly what
282 // this field does, but it
283 // shows up here and in the
284 // RecordStateTable, and
285 // for some of the records
286 // they must match when writing
290 } __attribute__ ((packed
));
291 #define DBC_TAGGED_UPLOAD_HEADER_SIZE (sizeof(Barry::Protocol::DBC_TaggedUpload) - 1)
293 struct DBC_IndexedUpload
295 uint8_t unknown
; // observed: 00 or 05
298 } __attribute__ ((packed
));
299 #define DBC_INDEXED_UPLOAD_HEADER_SIZE (sizeof(Barry::Protocol::DBC_IndexedUpload) - 1)
301 struct PasswordChallenge
303 uint8_t remaining_tries
; // number of password attempts
304 // the device will accept before
305 // committing suicide...
306 // starts at 10 and counts down
307 // on each bad password
308 uint8_t unknown
; // observed as 0... probably just
309 // the top byte of a uint16
310 // remaining_tries, but I don't
311 // want to take that chance
312 uint16_t param
; // seems to be a secondary command
313 // of some kind, observed as 0x14
314 // or 0x04, but purpose unknown
315 // possibly a send/receive flag
321 } __attribute__ ((packed
)) u
;
323 } __attribute__ ((packed
));
324 #define PASSWORD_CHALLENGE_HEADER_SIZE (sizeof(Barry::Protocol::PasswordChallenge) - sizeof(Barry::Protocol::PasswordChallenge::Hash))
325 #define PASSWORD_CHALLENGE_SEED_SIZE (PASSWORD_CHALLENGE_HEADER_SIZE + sizeof(uint32_t))
326 #define PASSWORD_CHALLENGE_SIZE (sizeof(Barry::Protocol::PasswordChallenge))
328 struct AttributeFetch
332 uint8_t raw
[1]; // used only in response
333 } __attribute__ ((packed
));
334 #define ATTRIBUTE_FETCH_COMMAND_SIZE (sizeof(Barry::Protocol::AttributeFetch) - 1)
342 } __attribute__ ((packed
)) response
;
343 } __attribute__ ((packed
));
346 ///////////////////////////////////////////////////////////////////////////////
347 // Protocol command structures
352 uint8_t sequence
; // incremented on each socket 0
353 // communication, replies return
354 // the same number from command
359 PasswordChallenge password
;
360 AttributeFetch fetch
;
364 } __attribute__ ((packed
)) u
;
365 } __attribute__ ((packed
));
366 #define SOCKET_COMMAND_HEADER_SIZE (sizeof(Barry::Protocol::SocketCommand) - sizeof(Barry::Protocol::SocketCommand::PacketData))
368 struct SequenceCommand
374 } __attribute__ ((packed
));
378 uint8_t operation
; // see below
379 uint16_t databaseId
; // value from the Database Database
385 DBC_RecordFlags flags
;
386 DBC_TaggedUpload tag_upload
;
387 DBC_IndexedUpload index_upload
;
390 } __attribute__ ((packed
)) u
;
391 } __attribute__ ((packed
));
392 #define DB_COMMAND_HEADER_SIZE (sizeof(Barry::Protocol::DBCommand) - sizeof(Barry::Protocol::DBCommand::Parameters))
396 ///////////////////////////////////////////////////////////////////////////////
397 // Protocol response parameter structures
399 struct DBR_OldDBDBRecord
401 uint16_t count
; // number of fields in record
402 OldDBDBField field
[1];
403 } __attribute__ ((packed
));
404 #define OLD_DBDB_RECORD_HEADER_SIZE (sizeof(Barry::Protocol::DBR_OldDBDBRecord) - sizeof(Barry::Protocol::OldDBDBField))
406 struct DBR_DBDBRecord
411 } __attribute__ ((packed
));
412 #define DBDB_RECORD_HEADER_SIZE (sizeof(Barry::Protocol::DBR_DBDBRecord) - sizeof(Barry::Protocol::DBDBField))
414 // Records with a uniqueId. This covers the following records:
416 // Old Contact records
417 // Old Service Book records
418 // Old Calendar records
420 struct DBR_OldTaggedRecord
429 CommonField field
[1];
430 } __attribute__ ((packed
)) u
;
431 } __attribute__ ((packed
));
432 #define DBR_OLD_TAGGED_RECORD_HEADER_SIZE (sizeof(Barry::Protocol::DBR_OldTaggedRecord) - sizeof(Barry::Protocol::DBR_OldTaggedRecord::TaggedData))
436 uint8_t field1
; // always 'j'
437 uint32_t field2
; // always 0x00000000
438 uint32_t flags
; // flags
439 uint32_t field4
; // normal email and pin recv this is 0x7ff
440 // changes on sent and reply to 0x01ffffff
441 // and 0x003fffff on pin send
442 uint32_t field5
; // always 0x00000000
443 uint32_t field6
; // always 0x00000000
444 uint32_t field7
; // always 0x00000000
445 uint32_t field8
; // always 0x00000000
446 uint16_t field9
; // always 0x0000
448 uint16_t dateReceived
; // the first two of these time fields are always the same
449 uint16_t timeReceived
; //
450 uint16_t dateDuplicate
; // On mail sent from the BB all three fields are identical
451 uint16_t timeDuplicate
; // (time sent)
455 uint16_t priority
; // priority field
456 uint32_t field14
; // always 0x00000000
457 uint32_t field15
; // always 0x00000000
458 uint16_t field16
; // always 0x0000
459 uint32_t field13
; // PIN reply 0x00000000 other time 0xffffffff or 0xfffffffe
460 uint16_t messageSize
; // Message size, 0x0000 if Reply or Saved, 0xffff if below ????
461 uint32_t field18
; // 0x0's and 0xF'x
462 uint32_t field19
; // 0x0's and 0xF's
463 uint16_t field20
; // always 0x0000
464 uint16_t field21
; // 0x01 unless PIN reply then 0x00
465 uint32_t inReplyTo
; // reply to message?
466 uint32_t field22
; // always 0x00000000
467 uint16_t field23
; // FIXME
469 uint32_t folderOne
; // these are the 'folders' the message is in
470 uint32_t folderTwo
; //
472 uint16_t replyMessageFlags
; // 0xfffe on recvd messages
477 uint16_t field27
; // set to 0x00000004 on PIN reply, 0x00000005 otherwise
478 uint32_t headerUID
; // yet another copy of the UID (RecId)
480 uint32_t field29
; // always 0x00000000
481 uint16_t field30
; // always 0x0002
482 uint16_t field31
; // always 0x00000000
483 uint16_t field32
; // always 0x0004
484 uint16_t field34
; // always 0x0000
485 uint8_t field33
; // always 'd'
486 uint32_t timeBlock
; // FIXME
487 CommonField field
[1];
488 } __attribute__ ((packed
));
489 #define MESSAGE_RECORD_HEADER_SIZE (sizeof(Barry::Protocol::MessageRecord) - sizeof(Barry::Protocol::CommonField))
493 ///////////////////////////////////////////////////////////////////////////////
494 // Protocol response structures
503 DBR_OldTaggedRecord tagged
;
504 DBR_OldDBDBRecord old_dbdb
;
507 } __attribute__ ((packed
)) u
;
509 } __attribute__ ((packed
));
510 #define DB_RESPONSE_HEADER_SIZE (sizeof(Barry::Protocol::DBResponse) - sizeof(Barry::Protocol::DBResponse::Parameters))
514 ///////////////////////////////////////////////////////////////////////////////
515 // Database access command structure
517 // even fragmented packets have a tableCmd
526 CommandTableField table
[1];
530 } __attribute__ ((packed
)) u
;
531 } __attribute__ ((packed
));
532 #define SB_DBACCESS_HEADER_SIZE (sizeof(Barry::Protocol::DBAccess) - sizeof(Barry::Protocol::DBAccess::DBData))
533 #define SB_DBACCESS_RETURN_CODE_SIZE (1)
537 ///////////////////////////////////////////////////////////////////////////////
538 // Main packet struct
542 uint16_t socket
; // socket ID... 0 exists by default
543 uint16_t size
; // total size of data packet
549 SocketCommand socket
;
550 SequenceCommand sequence
;
554 } __attribute__ ((packed
)) u
;
555 } __attribute__ ((packed
));
556 #define SB_PACKET_HEADER_SIZE (sizeof(Barry::Protocol::Packet) - sizeof(Barry::Protocol::Packet::PacketData))
558 // minimum required sizes for various responses
559 #define MIN_PACKET_SIZE 6
563 #define MAX_PACKET_SIZE 0x400 // anything beyond this needs to be
566 /////////////////////////////////////////////////////////////////////////////
568 // various useful sizes
571 #define SB_PACKET_DBACCESS_HEADER_SIZE (SB_PACKET_HEADER_SIZE + SB_DBACCESS_HEADER_SIZE)
572 #define SB_FRAG_HEADER_SIZE SB_PACKET_DBACCESS_HEADER_SIZE
574 #define SB_PACKET_COMMAND_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + DB_COMMAND_HEADER_SIZE)
575 #define SB_PACKET_RESPONSE_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + DB_RESPONSE_HEADER_SIZE)
577 #define SB_PACKET_DBDB_HEADER_SIZE (SB_PACKET_RESPONSE_HEADER_SIZE + DBDB_RECORD_HEADER_SIZE)
578 #define SB_PACKET_OLD_DBDB_HEADER_SIZE (SB_PACKET_RESPONSE_HEADER_SIZE + OLD_DBDB_RECORD_HEADER_SIZE)
580 #define SB_PACKET_UPLOAD_HEADER_SIZE (SB_PACKET_DBACCESS_HEADER_SIZE + UPLOAD_HEADER_SIZE)
582 #define SB_SEQUENCE_PACKET_SIZE (SB_PACKET_HEADER_SIZE + sizeof(Barry::Protocol::SequenceCommand))
583 #define SB_SOCKET_PACKET_HEADER_SIZE (SB_PACKET_HEADER_SIZE + SOCKET_COMMAND_HEADER_SIZE)
584 #define SB_MODE_PACKET_COMMAND_SIZE (SB_SOCKET_PACKET_HEADER_SIZE + sizeof(Barry::Protocol::ModeSelect) - sizeof(Barry::Protocol::ModeSelect::ResponseBlock))
585 #define SB_MODE_PACKET_RESPONSE_SIZE (SB_SOCKET_PACKET_HEADER_SIZE + sizeof(Barry::Protocol::ModeSelect))
589 #define COMMAND(data) (((const Barry::Protocol::Packet *)data.GetData())->command)
590 #define IS_COMMAND(data, cmd) (COMMAND(data) == cmd)
591 #define MAKE_PACKET(var, data) const Barry::Protocol::Packet *var = (const Barry::Protocol::Packet *) (data).GetData()
592 #define MAKE_PACKETPTR_BUF(var, ptr) Barry::Protocol::Packet *var = (Barry::Protocol::Packet *)ptr
593 #define MAKE_RECORD(type,var,data,off) type *var = (type *) ((data).GetData() + (off))
594 #define MAKE_RECORD_PTR(type,var,data,off) type *var = (type *) ((data) + (off))
596 // fragmentation protocol
597 // send DATA first, then keep sending DATA packets, FRAGMENTing
598 // as required until finished, then send DONE. Both sides behave
599 // this way, so different sized data can be sent in both
602 // the fragmented piece only has a the param header, and then continues
603 // right on with the data
607 // checks packet size and throws BError if not right
608 void CheckSize(const Barry::Data
&packet
, size_t requiredsize
= MIN_PACKET_SIZE
);
609 unsigned int GetSize(const Barry::Data
&packet
);
611 }} // namespace Barry::Protocol