Skip to content

Commit 0e37bbc

Browse files
committed
Merge branch 'ews-attach'
2 parents e3316fd + 94dc893 commit 0e37bbc

File tree

5 files changed

+117
-72
lines changed

5 files changed

+117
-72
lines changed

exch/ews/context.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,42 @@ void EWSContext::enableEventStream(int timeout)
684684
m_notify = std::make_unique<NotificationContext>(expire);
685685
}
686686

687+
/**
688+
* @brief Export message content to string
689+
*
690+
* @param dir Parent store
691+
* @param content Content to export
692+
* @param log_id Log ID
693+
*
694+
* @return Serialized content
695+
*/
696+
std::string EWSContext::exportContent(const std::string& dir, const MESSAGE_CONTENT& content, const std::string& log_id) const
697+
{
698+
MAIL mail;
699+
auto getPropIds = [&](const PROPNAME_ARRAY *names, PROPID_ARRAY *ids)
700+
{ *ids = getNamedPropIds(dir, *names); return TRUE; };
701+
auto getPropName = [&](uint16_t id, PROPERTY_NAME **name) { *name = getPropertyName(dir, id); return TRUE; };
702+
if (!oxcmail_export(&content, log_id.c_str(), false,
703+
oxcmail_body::plain_and_html, &mail, alloc, getPropIds, getPropName))
704+
throw EWSError::ItemCorrupt(E3072);
705+
auto mail_len = mail.get_length();
706+
if (mail_len < 0)
707+
throw EWSError::ItemCorrupt(E3073);
708+
STREAM tempStream;
709+
if (!mail.serialize(&tempStream))
710+
throw EWSError::ItemCorrupt(E3074);
711+
std::string mime;
712+
mime.reserve(mail_len);
713+
char *data;
714+
unsigned int size = STREAM_BLOCK_SIZE;
715+
while ((data = static_cast<char *>(tempStream.get_read_buf(&size))) != nullptr) {
716+
mime.insert(mime.end(), data, &data[size]);
717+
size = STREAM_BLOCK_SIZE;
718+
}
719+
return mime;
720+
}
721+
722+
687723
/**
688724
* @brief Get user or domain ID by name
689725
*
@@ -1101,7 +1137,19 @@ sAttachment EWSContext::loadAttachment(const std::string& dir, const sAttachment
11011137
PROPTAG_ARRAY tags{std::size(tagIDs), tagIDs};
11021138
if (!m_plugin.exmdb.get_instance_properties(dir.c_str(), 0, aInst->instanceId, &tags, &props))
11031139
throw DispatchError(E3083);
1104-
return tAttachment::create(aid, props);
1140+
sShape shape(props);
1141+
1142+
auto method = props.get<const uint32_t>(PR_ATTACH_METHOD);
1143+
if (method != nullptr && *method == ATTACH_EMBEDDED_MSG) {
1144+
auto eInst = m_plugin.loadEmbeddedInstance(dir, aInst->instanceId);
1145+
MESSAGE_CONTENT content{};
1146+
if (!m_plugin.exmdb.read_message_instance(dir.c_str(),
1147+
eInst->instanceId, &content))
1148+
throw DispatchError(E3208);
1149+
auto log_id = dir + ":a" + std::to_string(aid.attachment_num);
1150+
shape.mimeContent.emplace(exportContent(dir, content, log_id));
1151+
}
1152+
return tAttachment::create(aid, std::move(shape));
11051153
}
11061154

11071155
/**
@@ -1232,33 +1280,12 @@ void EWSContext::loadSpecial(const std::string& dir, uint64_t fid, uint64_t mid,
12321280
if (!exmdb.read_message(dir.c_str(), nullptr, CP_ACP, mid, &content) ||
12331281
content == nullptr)
12341282
throw EWSError::ItemNotFound(E3071);
1235-
MAIL mail;
1236-
auto getPropIds = [&](const PROPNAME_ARRAY* names, PROPID_ARRAY* ids)
1237-
{*ids = getNamedPropIds(dir, *names); return TRUE;};
1238-
auto getPropName = [&](uint16_t id, PROPERTY_NAME** name)
1239-
{*name = getPropertyName(dir, id); return TRUE;};
12401283
auto log_id = dir + ":m" + std::to_string(mid);
1241-
if (!oxcmail_export(content, log_id.c_str(), false,
1242-
oxcmail_body::plain_and_html, &mail, alloc, getPropIds, getPropName))
1243-
throw EWSError::ItemCorrupt(E3072);
1244-
auto mailLen = mail.get_length();
1245-
if (mailLen < 0)
1246-
throw EWSError::ItemCorrupt(E3073);
1247-
STREAM tempStream;
1248-
if (!mail.serialize(&tempStream))
1249-
throw EWSError::ItemCorrupt(E3074);
1250-
auto& mimeContent = item.MimeContent.emplace();
1251-
mimeContent.reserve(mailLen);
1252-
uint8_t* data;
1253-
unsigned int size = STREAM_BLOCK_SIZE;
1254-
while ((data = static_cast<uint8_t*>(tempStream.get_read_buf(&size))) != nullptr) {
1255-
mimeContent.insert(mimeContent.end(), data, data + size);
1256-
size = STREAM_BLOCK_SIZE;
1257-
}
1284+
item.MimeContent.emplace(exportContent(dir, *content, log_id));
12581285
}
12591286
if (special & sShape::Attachments) {
12601287
static uint32_t tagIDs[] = {PR_ATTACH_METHOD, PR_DISPLAY_NAME, PR_ATTACH_MIME_TAG, PR_ATTACH_CONTENT_ID,
1261-
PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_FLAGS};
1288+
PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_FLAGS, PR_ATTACH_SIZE};
12621289
auto mInst = m_plugin.loadMessageInstance(dir, fid, mid);
12631290
uint16_t count;
12641291
if (!exmdb.get_message_instance_attachments_num(dir.c_str(), mInst->instanceId, &count))
@@ -1272,7 +1299,7 @@ void EWSContext::loadSpecial(const std::string& dir, uint64_t fid, uint64_t mid,
12721299
if (!exmdb.get_instance_properties(dir.c_str(), 0, aInst->instanceId, &tags, &props))
12731300
throw DispatchError(E3080);
12741301
aid.attachment_num = i;
1275-
item.Attachments->emplace_back(tAttachment::create(aid, props));
1302+
item.Attachments->emplace_back(tAttachment::create(aid, sShape(props)));
12761303
}
12771304
}
12781305
if (special & sShape::Rights)

exch/ews/ews.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class EWSContext {
229229
const char* effectiveUser(const Structures::sFolderSpec&) const;
230230
void enableEventStream(int);
231231
std::string essdn_to_username(const std::string&) const;
232+
std::string exportContent(const std::string&, const MESSAGE_CONTENT&, const std::string&) const;
232233
std::string get_maildir(const Structures::tMailbox&) const;
233234
std::string get_maildir(const std::string&) const;
234235
uint32_t getAccountId(const std::string&, bool) const;

exch/ews/serialization.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,12 @@ void tEmailAddressDictionaryEntry::serialize(tinyxml2::XMLElement* xml) const
905905
XMLDUMPA(MailboxType);
906906
}
907907

908+
void tItemAttachment::serialize(tinyxml2::XMLElement *xml) const
909+
{
910+
tAttachment::serialize(xml);
911+
XMLDUMPT(Item);
912+
}
913+
908914
tFileAttachment::tFileAttachment(const XMLElement *xml)
909915
{
910916
if (const XMLElement *xp = xml->FirstChildElement("Name"))

exch/ews/structures.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,19 @@ T& defaulted(std::optional<T>& container, Args&&... args)
8989
*
9090
* @tparam T Type of the field
9191
* @tparam PT Type of the value contained in the property
92+
*
93+
* @return Reference to target
9294
*/
9395
template<typename T, typename PT=PropType<T>, std::enable_if_t<!std::is_same_v<PT, void>, bool> = true>
94-
void fromProp(const TAGGED_PROPVAL* prop, std::optional<T>& target)
96+
std::optional<T>& fromProp(const TAGGED_PROPVAL* prop, std::optional<T>& target)
9597
{
9698
if (!prop)
97-
return;
99+
return target;
98100
if constexpr (std::is_pointer_v<PT>)
99101
target.emplace(static_cast<PT>(prop->pvalue));
100102
else
101103
target.emplace(*static_cast<const PT*>(prop->pvalue));
104+
return target;
102105
}
103106

104107
/**
@@ -1320,30 +1323,30 @@ tAlternateId::tAlternateId(Enum::IdFormatType format, std::string id, std::strin
13201323
Mailbox(std::move(mailbox))
13211324
{}
13221325

1323-
tAttachment::tAttachment(const sAttachmentId& aid, const TPROPVAL_ARRAY& props)
1326+
tAttachment::tAttachment(const sAttachmentId& aid, const sShape& shape)
13241327
{
13251328
AttachmentId.emplace(aid);
1326-
fromProp(props.find(PR_ATTACH_LONG_FILENAME), Name);
1327-
fromProp(props.find(PR_ATTACH_MIME_TAG), ContentType);
1328-
fromProp(props.find(PR_ATTACH_CONTENT_ID), ContentId);
1329-
fromProp(props.find(PR_ATTACH_SIZE), Size);
1330-
fromProp(props.find(PR_LAST_MODIFICATION_TIME), LastModifiedTime);
1331-
auto flags = props.get<const uint32_t>(PR_ATTACH_FLAGS);
1329+
fromProp(shape.get(PR_ATTACH_LONG_FILENAME), Name) || fromProp(shape.get(PR_DISPLAY_NAME), Name);
1330+
fromProp(shape.get(PR_ATTACH_MIME_TAG), ContentType);
1331+
fromProp(shape.get(PR_ATTACH_CONTENT_ID), ContentId);
1332+
fromProp(shape.get(PR_ATTACH_SIZE), Size);
1333+
fromProp(shape.get(PR_LAST_MODIFICATION_TIME), LastModifiedTime);
1334+
auto flags = shape.get<const uint32_t>(PR_ATTACH_FLAGS);
13321335
if (flags != nullptr && *flags & ATT_MHTML_REF)
13331336
IsInline = true;
13341337
}
13351338

1336-
sAttachment tAttachment::create(const sAttachmentId& aid, const TPROPVAL_ARRAY& props)
1339+
sAttachment tAttachment::create(const sAttachmentId& aid, sShape&& shape)
13371340
{
1338-
const TAGGED_PROPVAL* prop = props.find(PR_ATTACH_METHOD);
1341+
const TAGGED_PROPVAL* prop = shape.get(PR_ATTACH_METHOD);
13391342
if (prop)
13401343
switch(*static_cast<const uint32_t*>(prop->pvalue)) {
13411344
case ATTACH_EMBEDDED_MSG:
1342-
return sAttachment(std::in_place_type_t<tItemAttachment>(), aid, props);
1345+
return sAttachment(std::in_place_type_t<tItemAttachment>(), aid, std::move(shape));
13431346
case ATTACH_BY_REFERENCE:
1344-
return sAttachment(std::in_place_type_t<tReferenceAttachment>(), aid, props);
1347+
return sAttachment(std::in_place_type_t<tReferenceAttachment>(), aid, std::move(shape));
13451348
}
1346-
return sAttachment(std::in_place_type_t<tFileAttachment>(), aid, props);
1349+
return sAttachment(std::in_place_type_t<tFileAttachment>(), aid, std::move(shape));
13471350
}
13481351

13491352
///////////////////////////////////////////////////////////////////////////////
@@ -3340,9 +3343,16 @@ uint32_t tFieldURI::tag(const sGetNameId& getId) const
33403343

33413344
///////////////////////////////////////////////////////////////////////////////
33423345

3343-
tFileAttachment::tFileAttachment(const sAttachmentId& aid, const TPROPVAL_ARRAY& props) : tAttachment(aid, props)
3346+
tItemAttachment::tItemAttachment(const sAttachmentId &aid, sShape &&shape) :
3347+
tAttachment(aid, shape)
3348+
{
3349+
Item.emplace(std::in_place_type_t<tMessage>(), sShape{});
3350+
std::get<tMessage>(*Item).MimeContent.emplace(std::move(*shape.mimeContent));
3351+
}
3352+
3353+
tFileAttachment::tFileAttachment(const sAttachmentId& aid, const sShape& shape) : tAttachment(aid, shape)
33443354
{
3345-
const TAGGED_PROPVAL *tp = props.find(PR_ATTACH_DATA_BIN);
3355+
const TAGGED_PROPVAL *tp = shape.get(PR_ATTACH_DATA_BIN);
33463356
if (tp) {
33473357
Content.emplace(*tp);
33483358
Size = Content->size();

exch/ews/structures.hpp

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,12 @@ using sAlternateId = std::variant<tAlternateId, tAlternatePublicFolderId, tAlter
516516
*/
517517
struct tAttachment : public NS_EWS_Types {
518518
tAttachment() = default;
519-
explicit tAttachment(const sAttachmentId&, const TPROPVAL_ARRAY&);
519+
explicit tAttachment(const sAttachmentId&, const sShape&);
520520

521-
static sAttachment create(const sAttachmentId&, const TPROPVAL_ARRAY&);
521+
static sAttachment create(const sAttachmentId&, sShape&&);
522522

523523
std::optional<sAttachmentId> AttachmentId;
524-
std::optional<std::string> Name;///< PR_ATTACH_LONG_FILENAM
524+
std::optional<std::string> Name;///< PR_ATTACH_LONG_FILENAME or PR_DISPLAYNAME
525525
std::optional<std::string> ContentType; ///< PR_ATTACH_MIME_TAG
526526
std::optional<std::string> ContentId; ///< PR_ATTACH_CONTENT_ID
527527
std::optional<std::string> ContentLocation;
@@ -953,7 +953,7 @@ struct tFileAttachment : public tAttachment {
953953

954954
tFileAttachment() = default;
955955
tFileAttachment(const tinyxml2::XMLElement *);
956-
tFileAttachment(const sAttachmentId&, const TPROPVAL_ARRAY&);
956+
tFileAttachment(const sAttachmentId&, const sShape&);
957957

958958
std::optional<bool> IsContactPhoto;
959959
std::optional<sBase64Binary> Content;
@@ -2133,33 +2133,6 @@ struct tContact : public tItem {
21332133
static void genFields(sShape&);
21342134
};
21352135

2136-
/**
2137-
* Types.xsd:1611
2138-
*/
2139-
struct tItemAttachment : public tAttachment {
2140-
static constexpr char NAME[] = "ItemAttachment";
2141-
2142-
//tItemAttachment(const sAttachmentId&, const TPROPVAL_ARRAY&);
2143-
using tAttachment::tAttachment;
2144-
2145-
//<xs:element name="Item" type="t:ItemType"/>
2146-
//<xs:element name="Message" type="t:MessageType"/>
2147-
//<xs:element name="SharingMessage" type="t:SharingMessageType"/>
2148-
//<xs:element name="CalendarItem" type="t:CalendarItemType"/>
2149-
//<xs:element name="Contact" type="t:ContactItemType"/>
2150-
//<xs:element name="MeetingMessage" type="t:MeetingMessageType"/>
2151-
//<xs:element name="MeetingRequest" type="t:MeetingRequestMessageType"/>
2152-
//<xs:element name="MeetingResponse" type="t:MeetingResponseMessageType"/>
2153-
//<xs:element name="MeetingCancellation" type="t:MeetingCancellationMessageType"/>
2154-
//<xs:element name="Task" type="t:TaskType"/>
2155-
//<xs:element name="PostItem" type="t:PostItemType"/>
2156-
//<xs:element name="RoleMember" type="t:RoleMemberItemType"/>
2157-
//<xs:element name="Network" type="t:NetworkItemType"/>
2158-
//<xs:element name="Person" type="t:AbchPersonItemType"/>
2159-
2160-
//void serialize(tinyxml2::XMLElement*) const;
2161-
};
2162-
21632136
struct tItemChange {
21642137
static constexpr char NAME[] = "ItemChange";
21652138

@@ -2553,6 +2526,34 @@ struct tDeclineItem : public tMessage {
25532526
std::optional<tItemId> ReferenceItemId;
25542527
};
25552528

2529+
/**
2530+
* Types.xsd:1611
2531+
*/
2532+
struct tItemAttachment : public tAttachment {
2533+
static constexpr char NAME[] = "ItemAttachment";
2534+
2535+
tItemAttachment() = default;
2536+
tItemAttachment(const sAttachmentId &, sShape &&);
2537+
2538+
//<xs:element name="Message" type="t:MessageType"/>
2539+
//<xs:element name="SharingMessage" type="t:SharingMessageType"/>
2540+
//<xs:element name="CalendarItem" type="t:CalendarItemType"/>
2541+
//<xs:element name="Contact" type="t:ContactItemType"/>
2542+
//<xs:element name="MeetingMessage" type="t:MeetingMessageType"/>
2543+
//<xs:element name="MeetingRequest" type="t:MeetingRequestMessageType"/>
2544+
//<xs:element name="MeetingResponse" type="t:MeetingResponseMessageType"/>
2545+
//<xs:element name="MeetingCancellation" type="t:MeetingCancellationMessageType"/>
2546+
//<xs:element name="Task" type="t:TaskType"/>
2547+
//<xs:element name="PostItem" type="t:PostItemType"/>
2548+
//<xs:element name="RoleMember" type="t:RoleMemberItemType"/>
2549+
//<xs:element name="Network" type="t:NetworkItemType"/>
2550+
//<xs:element name="Person" type="t:AbchPersonItemType"/>
2551+
2552+
std::optional<sItem> Item;
2553+
2554+
void serialize(tinyxml2::XMLElement *) const;
2555+
};
2556+
25562557
/**
25572558
* Joint item change type
25582559
*

0 commit comments

Comments
 (0)