From ed6ba5a558bccf6024c1a5ab3db2b89d4c6a1420 Mon Sep 17 00:00:00 2001 From: "Hoa V. DINH" Date: Fri, 5 Apr 2013 20:42:57 -0700 Subject: Documentation for abstract --- src/objc/abstract/MCOAbstractMessage.h | 4 + src/objc/abstract/MCOAbstractMessagePart.h | 4 + src/objc/abstract/MCOAbstractMultipart.h | 3 +- src/objc/abstract/MCOAbstractPart.h | 23 +++++ src/objc/abstract/MCOAddress.h | 16 ++++ src/objc/abstract/MCOConstants.h | 119 +++++++++++++++++++++++- src/objc/abstract/MCOHTMLRendererDelegate.h | 54 +++++++++++ src/objc/abstract/MCOHTMLRendererIMAPDelegate.h | 19 ++++ src/objc/abstract/MCOMessageHeader.h | 48 ++++++++-- 9 files changed, 280 insertions(+), 10 deletions(-) (limited to 'src/objc/abstract') diff --git a/src/objc/abstract/MCOAbstractMessage.h b/src/objc/abstract/MCOAbstractMessage.h index e506e31e..ea5df770 100644 --- a/src/objc/abstract/MCOAbstractMessage.h +++ b/src/objc/abstract/MCOAbstractMessage.h @@ -17,9 +17,13 @@ @interface MCOAbstractMessage : NSObject +// Header of the message. @property (nonatomic, strong) MCOMessageHeader * header; +// Returns the part with the given Content-ID. - (MCOAbstractPart *) partForContentID:(NSString *)contentID; + +// Returns the part with the given unique identifier. - (MCOAbstractPart *) partForUniqueID:(NSString *)uniqueID; @end diff --git a/src/objc/abstract/MCOAbstractMessagePart.h b/src/objc/abstract/MCOAbstractMessagePart.h index b7275a88..69a6a8f8 100644 --- a/src/objc/abstract/MCOAbstractMessagePart.h +++ b/src/objc/abstract/MCOAbstractMessagePart.h @@ -17,7 +17,11 @@ @interface MCOAbstractMessagePart : MCOAbstractPart +// Returns the header of the embedded message. @property (nonatomic, strong) MCOMessageHeader * header; + +// Returns the main part of the embedded message. It can be MCOAbstractPart, MCOAbstractMultipart +// or a MCOAbstractMessagePart. @property (nonatomic, strong) MCOAbstractPart * mainPart; @end diff --git a/src/objc/abstract/MCOAbstractMultipart.h b/src/objc/abstract/MCOAbstractMultipart.h index e39809ff..38f9dbe3 100644 --- a/src/objc/abstract/MCOAbstractMultipart.h +++ b/src/objc/abstract/MCOAbstractMultipart.h @@ -15,7 +15,8 @@ @interface MCOAbstractMultipart : MCOAbstractPart -@property (nonatomic, copy) NSArray * parts; +// Returns the subparts of that multipart. +@property (nonatomic, copy) NSArray * /* MCOAbstractPart */ parts; @end diff --git a/src/objc/abstract/MCOAbstractPart.h b/src/objc/abstract/MCOAbstractPart.h index bc1f3b7e..432863bf 100644 --- a/src/objc/abstract/MCOAbstractPart.h +++ b/src/objc/abstract/MCOAbstractPart.h @@ -24,17 +24,40 @@ typedef enum { @interface MCOAbstractPart : NSObject +// Returns type of the part (single / message part / multipart/mixed, +// multipart/related, multipart/alternative). See MCOPartType. @property (nonatomic, assign) MCOPartType partType; + +// Returns filename of the part. @property (nonatomic, copy) NSString * filename; + +// Returns MIME type of the part. For example application/data. @property (nonatomic, copy) NSString * mimeType; + +// Returns charset of the part in case it's a text single part. @property (nonatomic, copy) NSString * charset; + +// Returns the unique ID generated for this part. +// It's a unique identifier that's created when the object is created manually +// or created by the parser. @property (nonatomic, copy) NSString * uniqueID; + +// Returns the value of the Content-ID field of the part. @property (nonatomic, copy) NSString * contentID; + +// Returns the value of the Content-Location field of the part. @property (nonatomic, copy) NSString * contentLocation; + +// Returns whether the part is an explicit inline attachment. @property (nonatomic, assign, getter=isInlineAttachment) BOOL inlineAttachment; + +// Returns the owner message of the part. @property (nonatomic, weak) MCOAbstractMessage * message; +// Returns the part with the given Content-ID among this part and its subparts. - (MCOAbstractPart *) partForContentID:(NSString *)contentID; + +// Returns the part with the given unique identifier among this part and its subparts. - (MCOAbstractPart *) partForUniqueID:(NSString *)uniqueID; @end diff --git a/src/objc/abstract/MCOAddress.h b/src/objc/abstract/MCOAddress.h index 7362af93..7a741a04 100644 --- a/src/objc/abstract/MCOAddress.h +++ b/src/objc/abstract/MCOAddress.h @@ -14,19 +14,35 @@ @interface MCOAddress : NSObject +// Creates an address with a display name and a mailbox. +// Example: [MCOAddress addressWithDisplayName:@"DINH Viêt Hoà" mailbox:@"hoa@etpan.org"] + (MCOAddress *) addressWithDisplayName:(NSString *)displayName mailbox:(NSString *)mailbox; +// Creates an address with only a mailbox. +// Example: [MCOAddress addressWithMailbox:@"hoa@etpan.org"] + (MCOAddress *) addressWithMailbox:(NSString *)mailbox; +// Creates an address with a RFC822 string. +// Example: [MCOAddress addressWithRFC822String:@"DINH Vi=C3=AAt Ho=C3=A0 "] + (MCOAddress *) addressWithRFC822String:(NSString *)RFC822String; +// Creates an address with a non-MIME-encoded RFC822 string. +// Example: [MCOAddress addressWithRFC822String:@"DINH Viêt Hoà "] + (MCOAddress *) addressWithNonEncodedRFC822String:(NSString *)nonEncodedRFC822String; +// Returns the display name of the address. @property (nonatomic, copy) NSString * displayName; + +// Returns the mailbox of the address. @property (nonatomic, copy) NSString * mailbox; +// Returns the RFC822 encoding of the address. +// For example: "DINH Vi=C3=AAt Ho=C3=A0 " - (NSString *) RFC822String; + +// Returns the non-MIME-encoded RFC822 encoding of the address. +// For example: "DINH Viêt Hoà " - (NSString *) nonEncodedRFC822String; @end diff --git a/src/objc/abstract/MCOConstants.h b/src/objc/abstract/MCOConstants.h index 0412ba9c..e014795d 100644 --- a/src/objc/abstract/MCOConstants.h +++ b/src/objc/abstract/MCOConstants.h @@ -2,130 +2,243 @@ #define __MAILCORE_MCOCONSTANTS_H_ +// It's the connection type. typedef enum { + // Clear-text connection for the protocol. MCOConnectionTypeClear = 1 << 0, + // Clear-text connection at the beginning, then switch to encrypted connection using TLS/SSL + // on the same TCP connection. MCOConnectionTypeStartTLS = 1 << 1, + // Encrypted connection using TLS/SSL. MCOConnectionTypeTLS = 1 << 2, } MCOConnectionType; +// It's the authentication type. typedef enum { + // Default authentication scheme of the protocol. MCOAuthTypeSASLNone = 0, + // CRAM-MD5 authentication RFC 2195. MCOAuthTypeSASLCRAMMD5 = 1 << 0, + // PLAIN authentication RFC 4616. MCOAuthTypeSASLPlain = 1 << 1, + // GSSAPI authentication. MCOAuthTypeSASLGSSAPI = 1 << 2, + // DIGEST-MD5 authentication RFC 2831. MCOAuthTypeSASLDIGESTMD5 = 1 << 3, + // LOGIN authentication http://tools.ietf.org/id/draft-murchison-sasl-login-00.txt MCOAuthTypeSASLLogin = 1 << 4, + // Secure Remote Password Authentication http://tools.ietf.org/html/draft-burdis-cat-srp-sasl-08 MCOAuthTypeSASLSRP = 1 << 5, + // NTLM authentication. MCOAuthTypeSASLNTLM = 1 << 6, + // Kerberos 4 authentication. MCOAuthTypeSASLKerberosV4 = 1 << 7, } MCOAuthType; +// It's the IMAP flags of the folder. typedef enum { MCOIMAPFolderFlagNone = 0, + // \Marked MCOIMAPFolderFlagMarked = 1 << 0, + // \Unmarked MCOIMAPFolderFlagUnmarked = 1 << 1, + // \NoSelect: When a folder can't be selected. MCOIMAPFolderFlagNoSelect = 1 << 2, + // \NoInferiors: When the folder has no children. MCOIMAPFolderFlagNoInferiors = 1 << 3, + // \Inbox: When the folder is the inbox. MCOIMAPFolderFlagInbox = 1 << 4, + // \Sent: When the folder is the sent folder. MCOIMAPFolderFlagSentMail = 1 << 5, + // \Starred: When the folder is the starred folder MCOIMAPFolderFlagStarred = 1 << 6, + // \AllMail: When the folder is all mail. MCOIMAPFolderFlagAllMail = 1 << 7, + // \Trash: When the folder is the trash. MCOIMAPFolderFlagTrash = 1 << 8, + // \Drafts: When the folder is the drafts folder. MCOIMAPFolderFlagDrafts = 1 << 9, + // \Spam: When the folder is the spam folder. MCOIMAPFolderFlagSpam = 1 << 10, + // \Important: When the folder is the important folder. MCOIMAPFolderFlagImportant = 1 << 11, + // \Archive: When the folder is archive. MCOIMAPFolderFlagArchive = 1 << 12, + // \All: When the folder contains all mails, similar to \AllMail. + MCOIMAPFolderFlagAll = MCOIMAPFolderFlagAllMail, + // \Junk: When the folder is the spam folder. + MCOIMAPFolderFlagJunk = MCOIMAPFolderFlagSpam, + // \Flagged: When the folder contains all the flagged emails. + MCOIMAPFolderFlagFlagged = MCOIMAPFolderFlagStarred, } MCOIMAPFolderFlag; +// It's the flags of a message. typedef enum { MCOMessageFlagNone = 0, + // Seen/Read flag. MCOMessageFlagSeen = 1 << 0, + // Replied/Answered flag. MCOMessageFlagAnswered = 1 << 1, + // Flagged/Starred flag. MCOMessageFlagFlagged = 1 << 2, + // Deleted flag. MCOMessageFlagDeleted = 1 << 3, + // Draft flag. MCOMessageFlagDraft = 1 << 4, + // $MDNSent flag. MCOMessageFlagMDNSent = 1 << 5, + // $Forwarded flag. MCOMessageFlagForwarded = 1 << 6, + // $SubmitPending flag. MCOMessageFlagSubmitPending = 1 << 7, + // $Submitted flag. MCOMessageFlagSubmitted = 1 << 8, } MCOMessageFlag; +// It's the encoding of a part. typedef enum { + // 7bit encoding. MCOEncoding7Bit = 0, // should match MAILIMAP_BODY_FLD_ENC_7BIT + // 8bit encoding. MCOEncoding8Bit = 1, // should match MAILIMAP_BODY_FLD_ENC_8BIT + // binary encoding. MCOEncodingBinary = 2, // should match MAILIMAP_BODY_FLD_ENC_BINARY + // base64 encoding. MCOEncodingBase64 = 3, // should match MAILIMAP_BODY_FLD_ENC_BASE64 + // quoted-printable encoding. MCOEncodingQuotedPrintable = 4, // should match MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE + // other encoding. MCOEncodingOther = 5, // should match MAILIMAP_BODY_FLD_ENC_OTHER - // negative values should be used for other encoding + + // Negative values should be used for encoding not supported by libetpan. + + // UUEncode encoding. MCOEncodingUUEncode = -1 } MCOEncoding; +// It's the information to fetch for a given message in the IMAP FETCH request. typedef enum { + // UID of the message. MCOIMAPMessagesRequestKindUid = 0, // This is the default and it's always fetched + // Flags of the message. MCOIMAPMessagesRequestKindFlags = 1 << 0, + // Headers of the message (parsed by the server). MCOIMAPMessagesRequestKindHeaders = 1 << 1, + // MIME structure of the message. MCOIMAPMessagesRequestKindStructure = 1 << 2, + // Received date. MCOIMAPMessagesRequestKindInternalDate = 1 << 3, + // Headers through headers data. MCOIMAPMessagesRequestKindFullHeaders = 1 << 4, + // Subject of the message. MCOIMAPMessagesRequestKindHeaderSubject = 1 << 5, + // Gmail Labels. MCOIMAPMessagesRequestKindGmailLabels = 1 << 6, } MCOIMAPMessagesRequestKind; +// It defines the behavior of the STORE flags request. typedef enum { + // Add the given flags. MCOIMAPStoreFlagsRequestKindAdd, + // Remove the given flags. MCOIMAPStoreFlagsRequestKindRemove, + // Set the given flags. MCOIMAPStoreFlagsRequestKindSet, } MCOIMAPStoreFlagsRequestKind; +// It's the search type. typedef enum { + // No search. MCOIMAPSearchKindNone, + // Match sender. MCOIMAPSearchKindFrom, + // Match recipient. MCOIMAPSearchKindRecipient, + // Match subject. MCOIMAPSearchKindSubject, + // Match content of the message. MCOIMAPSearchKindContent, + // Match headers of the message. MCOIMAPSearchKindHeader, + // Or expresssion. MCOIMAPSearchKindOr, + // And expression. MCOIMAPSearchKindAnd, } MCOIMAPSearchKind; +// Here's the list of errors. typedef enum { + // No error occurred. MCOErrorNone, + // An error related to the connection occurred. + // It could not connect or it's been disconnected. MCOErrorConnection, + // TLS/SSL connection was not available. MCOErrorTLSNotAvailable, - MCOErrorTLSCertificate, + // The protocol could not be parsed. MCOErrorParse, + // Certificate was not valid. MCOErrorCertificate, + // An authentication error occurred. MCOErrorAuthentication, + // Specific to Gmail: IMAP not enabled. MCOErrorGmailIMAPNotEnabled, + // Specific to Gmail: Exceeded bandwidth limit. MCOErrorGmailExceededBandwidthLimit, + // Specific to Gmail: Too many simultaneous connections. MCOErrorGmailTooManySimultaneousConnections, + // Specific to Mobile Me: Moved to iCloud. MCOErrorMobileMeMoved, + // Specific to Yahoo: not available. MCOErrorYahooUnavailable, + // Non existant folder, select failed. MCOErrorNonExistantFolder, + // IMAP: Error occurred while renaming a folder. MCOErrorRename, + // IMAP: Error occurred while deleting a folder. MCOErrorDelete, + // IMAP: Error occurred while creating a folder. MCOErrorCreate, + // IMAP: Error occurred while subscribing/unsubcribing to a folder. MCOErrorSubscribe, + // IMAP: Error occurred while adding a message to a folder. MCOErrorAppend, + // IMAP: Error occurred while copying a message. MCOErrorCopy, + // IMAP: Error occurred while expunging. MCOErrorExpunge, + // IMAP: Error occurred while fetching messages. MCOErrorFetch, + // IMAP: Error occurred while IDLing. MCOErrorIdle, + // IMAP: Error occurred while sending/getting identity. MCOErrorIdentity, + // IMAP: Error occurred while getting namespace. MCOErrorNamespace, + // IMAP: Error occurred while storing flags. MCOErrorStore, + // IMAP: Error wile getting capabilities. + MCOErrorCapability, + // STARTTLS is not available. MCOErrorStartTLSNotAvailable, + // SMTP: Illegal attachment: certain kind of attachment cannot be sent. MCOErrorSendMessageIllegalAttachment, + // SMTP: Storage limit: message is probably too big. MCOErrorStorageLimit, + // SMTP: Sending message is not allowed. MCOErrorSendMessageNotAllowed, + // SMTP: Specific to hotmail. Needs to connect to webmail. MCOErrorNeedsConnectToWebmail, + // SMTP: Error while sending message. MCOErrorSendMessage, + // SMTP: Authentication required. MCOErrorAuthenticationRequired, + // POP: Error occurred while fetching message list. MCOErrorFetchMessageList, + // POP: Error occurred while deleting message. MCOErrorDeleteMessage, + // SMTP: Error while checking account. MCOErrorInvalidAccount, - MCOErrorCapability, } MCOErrorCode; #endif diff --git a/src/objc/abstract/MCOHTMLRendererDelegate.h b/src/objc/abstract/MCOHTMLRendererDelegate.h index 1f9fe663..1e939a91 100644 --- a/src/objc/abstract/MCOHTMLRendererDelegate.h +++ b/src/objc/abstract/MCOHTMLRendererDelegate.h @@ -12,24 +12,78 @@ #import +// This delegate protocol is used to help rendering of the message. +// +// It will be used for the following methods. +// +// -[MCOMessageParser htmlRenderingWithDelegate:], +// -[MCOMessageBuilder htmlRenderingWithDelegate:] +// -[MCOIMAPMessage htmlRenderingWithFolder:delegate:] + @class MCOAbstractPart; @class MCOAbstractMessage; @class MCOMessageHeader; @protocol MCOHTMLRendererDelegate +// All methods are optional. +@optional + +// This delegate method should return YES if it can render a preview of the attachment as an image. +// part is always a single part. +// If the attachment can be previewed, it will be rendered using the image template. +// If not, the attachment template will be used. - (BOOL) MCOAbstractMessage:(MCOAbstractMessage *)msg canPreviewPart:(MCOAbstractPart *)part; + +// This delegate method returns the values to be applied to the template for the given header. +// See the content of MCHTMLRendererCallback.cpp for the default values of the header. - (NSDictionary *) MCOAbstractMessage:(MCOAbstractMessage *)msg templateValuesForHeader:(MCOMessageHeader *)header; + +// This delegate method returns the values to be applied to the template for the given attachment. +// See the content of MCHTMLRendererCallback.cpp for the default values of the attachment. - (NSDictionary *) MCOAbstractMessage:(MCOAbstractMessage *)msg templateValuesForPart:(MCOAbstractPart *)part; + +// The following methods returns templates. They will match the syntax of ctemplate. +// See https://code.google.com/p/ctemplate/ + +// This delegate method returns the template for the main header of the message. +// See the content of MCHTMLRendererCallback.cpp for the default values of the template. - (NSString *) MCOAbstractMessage_templateForMainHeader:(MCOAbstractMessage *)msg; + +// This delegate method returns the template an image attachment. - (NSString *) MCOAbstractMessage_templateForImage:(MCOAbstractMessage *)msg; + +// This delegate method returns the template attachment other than images. +// See the content of MCHTMLRendererCallback.cpp for the default values of the template. - (NSString *) MCOAbstractMessage_templateForAttachment:(MCOAbstractMessage *)msg; + +// This delegate method returns the template of the main message. +// It should include HEADER and a BODY values. +// See the content of MCHTMLRendererCallback.cpp for the default values of the template. - (NSString *) MCOAbstractMessage_templateForMessage:(MCOAbstractMessage *)msg; + +// This delegate method returns the template of an embedded message (included as attachment). +// It should include HEADER and a BODY values. +// See the content of MCHTMLRendererCallback.cpp for the default values of the template. - (NSString *) MCOAbstractMessage_templateForEmbeddedMessage:(MCOAbstractMessage *)msg; + +// This delegate method returns the template for the header of an embedded message. +// See the content of MCHTMLRendererCallback.cpp for the default values of the template. - (NSString *) MCOAbstractMessage_templateForEmbeddedMessageHeader:(MCOAbstractMessage *)msg; + +// This delegate method returns the separator between the text of the message and the attachments. +// This delegate method returns the template for the header of an embedded message. - (NSString *) MCOAbstractMessage_templateForAttachmentSeparator:(MCOAbstractMessage *)msg; +// The following methods will filter the HTML content and may apply some filters to +// change how to display the message. + +// This delegate method will apply the filter to HTML rendered content of a given text part. +// For example, it could filter the CSS content. - (NSString *) MCOAbstractMessage:(MCOAbstractMessage *)msg filterHTMLForPart:(NSString *)html; + +// This delegate method will apply a filter to the whole HTML content. +// For example, it could collapse the quoted messages. - (NSString *) MCOAbstractMessage:(MCOAbstractMessage *)msg filterHTMLForMessage:(NSString *)html; @end diff --git a/src/objc/abstract/MCOHTMLRendererIMAPDelegate.h b/src/objc/abstract/MCOHTMLRendererIMAPDelegate.h index 509e5b5d..562256c3 100644 --- a/src/objc/abstract/MCOHTMLRendererIMAPDelegate.h +++ b/src/objc/abstract/MCOHTMLRendererIMAPDelegate.h @@ -12,12 +12,31 @@ #import +// This delegate protocol is used to fetch the content of the part of the message when the HTML render needs them. +// It will help fetch the minimal amount of information from the message required to render the HTML. +// +// It will be used for the following method. +// +// -[MCOIMAPMessage htmlRenderingWithFolder:delegate:] + @class MCOIMAPPart; @protocol MCOHTMLRendererIMAPDelegate +// All methods are optional. +@optional + +// The delegate method returns NULL if the delegate have not fetch the part yet. The opportunity can also be used to +// start fetching the attachment. +// It will return the data synchronously if it has already fetched it. - (NSData *) MCOAbstractMessage:(MCOAbstractMessage *)msg dataForIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder; + +// The delegate method will notify the delegate to start fetching the given part. +// It will be used to render an attachment that cannot be previewed. - (void) MCOAbstractMessage:(MCOAbstractMessage *)msg prefetchAttachmentIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder; + +// The delegate method will notify the delegate to start fetching the given part. +// It will be used to render an attachment that can be previewed. - (void) MCOAbstractMessage:(MCOAbstractMessage *)msg prefetchImageIMAPPart:(MCOIMAPPart *)part folder:(NSString *)folder; @end diff --git a/src/objc/abstract/MCOMessageHeader.h b/src/objc/abstract/MCOMessageHeader.h index a0eca023..899f8d38 100644 --- a/src/objc/abstract/MCOMessageHeader.h +++ b/src/objc/abstract/MCOMessageHeader.h @@ -12,31 +12,67 @@ #import +// This class implements common fields of a message header. + @class MCOAddress; @interface MCOMessageHeader : NSObject +// Message-ID field. @property (nonatomic, copy) NSString * messageID; -@property (nonatomic, copy) NSArray * references; -@property (nonatomic, copy) NSArray * inReplyTo; + +// References field. It's an array of message-ids. +@property (nonatomic, copy) NSArray * /* NSString */ references; + +// In-Reply-To field. It's an array of message-ids. +@property (nonatomic, copy) NSArray * /* NSString */ inReplyTo; + +// Date field: sent date of the message. @property (nonatomic, strong) NSDate * date; + +// Received date: received date of the message. @property (nonatomic, strong) NSDate * receivedDate; + +// Sender field. @property (nonatomic, copy) MCOAddress * sender; + +// From field: address of the sender of the message. @property (nonatomic, copy) MCOAddress * from; -@property (nonatomic, copy) NSArray * to; -@property (nonatomic, copy) NSArray * cc; -@property (nonatomic, copy) NSArray * bcc; -@property (nonatomic, copy) NSArray * replyTo; + +// To field: recipient of the message. It's an array of MCOAddress. +@property (nonatomic, copy) NSArray * /* MCOAddress */ to; + +// Cc field: cc recipient of the message. It's an array of MCOAddress. +@property (nonatomic, copy) NSArray * /* MCOAddress */ cc; + +// Bcc field: bcc recipient of the message. It's an array of MCOAddress. +@property (nonatomic, copy) NSArray * /* MCOAddress */ bcc; + +// Reply-To field. It's an array of MCOAddress. +@property (nonatomic, copy) NSArray * /* MCOAddress */ replyTo; + +// Subject of the message. @property (nonatomic, copy) NSString * subject; + +// User-Agent. @property (nonatomic, copy) NSString * userAgent; +// Extracted subject (also remove square brackets). - (NSString *) extractedSubject; + +// Extracted subject (don't remove square brackets). - (NSString *) partialExtractedSubject; +// Fill the header using the given RFC 822 data. - (void) importHeadersData:(NSData *)data; +// Returns a header that can be used as a base for a reply message. - (MCOMessageHeader *) replyHeaderWithExcludedRecipients:(NSArray *)excludedRecipients; + +// Returns a header that can be used as a base for a reply all message. - (MCOMessageHeader *) replyAllHeaderWithExcludedRecipients:(NSArray *)excludedRecipients; + +// Returns a header that can be used as a base for a forward message. - (MCOMessageHeader *) forwardHeader; @end -- cgit v1.2.3