Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
BC
public
liblinphone
Commits
0c9fbfc1
Commit
0c9fbfc1
authored
Sep 13, 2017
by
Sylvain Berfini
🐮
Browse files
Improved CPIM parser to parse all MIME-encapsulated message content headers
parent
3d30114e
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/chat/cpim/message/cpim-message.cpp
View file @
0c9fbfc1
...
...
@@ -20,6 +20,7 @@
#include "linphone/utils/utils.h"
#include "logger/logger.h"
#include "chat/cpim/parser/cpim-parser.h"
#include "object/object-p.h"
...
...
@@ -37,6 +38,7 @@ public:
shared_ptr
<
PrivHeaderList
>
cpimHeaders
=
make_shared
<
PrivHeaderList
>
();
shared_ptr
<
PrivHeaderList
>
messageHeaders
=
make_shared
<
PrivHeaderList
>
();
shared_ptr
<
PrivHeaderList
>
contentHeaders
=
make_shared
<
PrivHeaderList
>
();
string
content
;
};
...
...
@@ -92,6 +94,30 @@ void Cpim::Message::removeMessageHeader (const Header &messageHeader) {
// -----------------------------------------------------------------------------
Cpim
::
Message
::
HeaderList
Cpim
::
Message
::
getContentHeaders
()
const
{
L_D
(
const
Message
);
return
d
->
contentHeaders
;
}
bool
Cpim
::
Message
::
addContentHeader
(
const
Header
&
contentHeader
)
{
L_D
(
Message
);
if
(
!
contentHeader
.
isValid
())
return
false
;
d
->
contentHeaders
->
push_back
(
Parser
::
getInstance
()
->
cloneHeader
(
contentHeader
));
return
true
;
}
void
Cpim
::
Message
::
removeContentHeader
(
const
Header
&
contentHeader
)
{
L_D
(
Message
);
d
->
contentHeaders
->
remove_if
([
&
contentHeader
](
const
shared_ptr
<
const
Header
>
&
header
)
{
return
contentHeader
.
getName
()
==
header
->
getName
()
&&
contentHeader
.
getValue
()
==
header
->
getValue
();
});
}
// -----------------------------------------------------------------------------
string
Cpim
::
Message
::
getContent
()
const
{
L_D
(
const
Message
);
return
d
->
content
;
...
...
@@ -125,11 +151,18 @@ string Cpim::Message::asString () const {
output
+=
"
\r\n
"
;
for
(
const
auto
&
messageHeader
:
*
d
->
messageHeaders
)
output
+=
messageHeader
->
asString
();
if
(
d
->
messageHeaders
->
size
()
>
0
)
{
for
(
const
auto
&
messageHeader
:
*
d
->
messageHeaders
)
output
+=
messageHeader
->
asString
();
output
+=
"
\r\n
"
;
}
for
(
const
auto
&
contentHeaders
:
*
d
->
contentHeaders
)
output
+=
contentHeaders
->
asString
();
output
+=
"
\r\n
"
;
output
+=
""
;
// TODO: Headers MIME.
output
+=
getContent
();
return
output
;
...
...
src/chat/cpim/message/cpim-message.h
View file @
0c9fbfc1
...
...
@@ -42,6 +42,10 @@ namespace Cpim {
HeaderList
getMessageHeaders
()
const
;
bool
addMessageHeader
(
const
Header
&
messageHeader
);
void
removeMessageHeader
(
const
Header
&
messageHeader
);
HeaderList
getContentHeaders
()
const
;
bool
addContentHeader
(
const
Header
&
contentHeader
);
void
removeContentHeader
(
const
Header
&
contentHeader
);
std
::
string
getContent
()
const
;
bool
setContent
(
const
std
::
string
&
content
);
...
...
src/chat/cpim/parser/cpim-grammar.cpp
View file @
0c9fbfc1
...
...
@@ -25,7 +25,7 @@ LINPHONE_BEGIN_NAMESPACE
static
const
char
*
grammar
=
// See: https://tools.ietf.org/html/rfc3862
R"==GRAMMAR==(
Message = Headers CRLF Headers CRLF
Message = Headers CRLF Headers CRLF
[Headers CRLF]
Headers = *Header
Header = Header-name ":" Header-parameters SP Header-value CRLF
...
...
src/chat/cpim/parser/cpim-parser.cpp
View file @
0c9fbfc1
...
...
@@ -166,7 +166,7 @@ namespace Cpim {
// Warning: Call this function one time!
shared_ptr
<
Message
>
createMessage
()
const
{
size_t
size
=
mHeaders
->
size
();
if
(
size
!=
2
)
{
if
(
size
<
2
||
size
>
3
)
{
lWarning
()
<<
"Bad headers lists size."
;
return
nullptr
;
}
...
...
@@ -190,9 +190,21 @@ namespace Cpim {
}
// Add message headers.
if
(
mHeaders
->
size
()
>
2
)
{
list
<
shared_ptr
<
ListHeaderNode
>>::
iterator
it
=
mHeaders
->
begin
();
std
::
advance
(
it
,
1
);
shared_ptr
<
ListHeaderNode
>
messageHeaders
=
*
it
;
for
(
const
auto
&
headerNode
:
*
messageHeaders
)
{
const
shared_ptr
<
const
Header
>
header
=
headerNode
->
createHeader
();
if
(
!
header
||
!
message
->
addMessageHeader
(
*
header
))
return
nullptr
;
}
}
// Add content headers.
for
(
const
auto
&
headerNode
:
*
mHeaders
->
back
())
{
const
shared_ptr
<
const
Header
>
header
=
headerNode
->
createHeader
();
if
(
!
header
||
!
message
->
add
Message
Header
(
*
header
))
if
(
!
header
||
!
message
->
add
Content
Header
(
*
header
))
return
nullptr
;
}
...
...
@@ -265,8 +277,9 @@ shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
}
shared_ptr
<
Message
>
message
=
messageNode
->
createMessage
();
if
(
message
)
if
(
message
)
{
message
->
setContent
(
input
.
substr
(
parsedSize
));
}
return
message
;
}
...
...
src/chat/modifier/cpim-chat-message-modifier.cpp
View file @
0c9fbfc1
...
...
@@ -31,10 +31,10 @@
void
CpimChatMessageModifier
::
encode
(
LinphonePrivate
::
ChatMessagePrivate
*
msg
)
{
Cpim
::
Message
message
;
Cpim
::
GenericHeader
contentTypeHeader
;
contentTypeHeader
.
setName
(
"Content-Type"
);
contentTypeHeader
.
setValue
(
"Message/CPIM"
);
message
.
addCpimHeader
(
contentTypeHeader
);
Cpim
::
GenericHeader
c
pimC
ontentTypeHeader
;
c
pimC
ontentTypeHeader
.
setName
(
"Content-Type"
);
c
pimC
ontentTypeHeader
.
setValue
(
"Message/CPIM"
);
message
.
addCpimHeader
(
c
pimC
ontentTypeHeader
);
shared_ptr
<
Content
>
content
;
if
(
msg
->
internalContent
)
{
...
...
@@ -50,7 +50,13 @@
string
contentType
=
content
->
getContentType
().
asString
();
const
vector
<
char
>
body
=
content
->
getBody
();
string
contentBody
(
body
.
begin
(),
body
.
end
());
message
.
setContent
(
"ContentType: "
+
contentType
+
"
\r\n
"
+
contentBody
);
Cpim
::
GenericHeader
contentTypeHeader
;
contentTypeHeader
.
setName
(
"Content-Type"
);
contentTypeHeader
.
setValue
(
contentType
);
message
.
addContentHeader
(
contentTypeHeader
);
message
.
setContent
(
contentBody
);
if
(
!
message
.
isValid
())
{
//TODO
...
...
@@ -64,7 +70,29 @@
}
void
CpimChatMessageModifier
::
decode
(
LinphonePrivate
::
ChatMessagePrivate
*
msg
)
{
//TODO
shared_ptr
<
Content
>
content
;
if
(
msg
->
internalContent
)
{
content
=
msg
->
internalContent
;
}
else
{
content
=
msg
->
contents
.
front
();
}
ContentType
contentType
=
content
->
getContentType
();
if
(
contentType
.
asString
()
==
"Message/CPIM"
)
{
const
vector
<
char
>
body
=
content
->
getBody
();
string
contentBody
(
body
.
begin
(),
body
.
end
());
shared_ptr
<
const
Cpim
::
Message
>
message
=
Cpim
::
Message
::
createFromString
(
contentBody
);
if
(
message
&&
message
->
isValid
())
{
shared_ptr
<
Content
>
newContent
=
make_shared
<
Content
>
();
ContentType
newContentType
(
message
->
getContentHeaders
()
->
front
()
->
getValue
());
newContent
->
setContentType
(
newContentType
);
newContent
->
setBody
(
message
->
getContent
());
}
else
{
//TODO
}
}
else
{
//TODO
}
}
LINPHONE_END_NAMESPACE
\ No newline at end of file
src/content/content-type.cpp
View file @
0c9fbfc1
...
...
@@ -70,6 +70,10 @@ bool ContentType::operator== (const ContentType &contentType) {
return
getType
()
==
contentType
.
getType
()
&&
getSubType
()
==
contentType
.
getSubType
();
}
bool
ContentType
::
operator
==
(
const
string
&
contentType
)
{
return
*
this
==
ContentType
(
contentType
);
}
const
string
&
ContentType
::
getType
()
const
{
L_D
(
const
ContentType
);
return
d
->
type
;
...
...
src/content/content-type.h
View file @
0c9fbfc1
...
...
@@ -38,6 +38,7 @@ public:
ContentType
&
operator
=
(
const
ContentType
&
src
);
bool
operator
==
(
const
ContentType
&
contentType
);
bool
operator
==
(
const
std
::
string
&
contentType
);
bool
isValid
()
const
;
...
...
tester/cpim-tester.cpp
View file @
0c9fbfc1
...
...
@@ -37,6 +37,8 @@ static void parse_minimal_message () {
const
string
str2
=
message
->
asString
();
BC_ASSERT_STRING_EQUAL
(
str2
.
c_str
(),
str
.
c_str
());
BC_ASSERT_STRING_EQUAL
(
message
->
getContent
().
c_str
(),
""
);
}
static
void
set_generic_header_name
()
{
...
...
@@ -227,6 +229,10 @@ static void check_subject_header_language () {
}
static
void
parse_rfc_example
()
{
const
string
body
=
"<body>"
"Here is the text of my message."
"</body>"
;
const
string
str
=
"Content-type: Message/CPIM
\r\n
"
"
\r\n
"
"From: MR SANDERS <im:piglet@100akerwood.com>
\r\n
"
...
...
@@ -239,21 +245,25 @@ static void parse_rfc_example () {
"MyFeatures.VitalMessageOption: Confirmation-requested
\r\n
"
"MyFeatures.WackyMessageOption: Use-silly-font
\r\n
"
"
\r\n
"
"Content-
t
ype text/xml; charset=utf-8
\r\n
"
"Content-
T
ype
:
text/xml; charset=utf-8
\r\n
"
"Content-ID: <1234567890@foo.com>
\r\n
"
"
\r\n
"
"<body>"
"Here is the text of my message."
"</body>"
;
"
\r\n
"
+
body
;
shared_ptr
<
const
Cpim
::
Message
>
message
=
Cpim
::
Message
::
createFromString
(
str
);
if
(
!
BC_ASSERT_PTR_NOT_NULL
(
message
))
return
;
const
string
str2
=
message
->
asString
();
BC_ASSERT_STRING_EQUAL
(
str2
.
c_str
(),
str
.
c_str
());
string
content
=
message
->
getContent
();
BC_ASSERT_STRING_EQUAL
(
content
.
c_str
(),
body
.
c_str
());
}
static
void
parse_message_with_generic_header_parameters
()
{
const
string
body
=
"<body>"
"Here is the text of my message."
"</body>"
;
const
string
str
=
"Content-type: Message/CPIM
\r\n
"
"
\r\n
"
"From: MR SANDERS <im:piglet@100akerwood.com>
\r\n
"
...
...
@@ -261,18 +271,18 @@ static void parse_message_with_generic_header_parameters () {
"yaya: coucou
\r\n
"
"yepee:;good=bad ugly
\r\n
"
"
\r\n
"
"Content-
t
ype text/xml; charset=utf-8
\r\n
"
"Content-
T
ype
:
text/xml; charset=utf-8
\r\n
"
"Content-ID: <1234567890@foo.com>
\r\n
"
"
\r\n
"
"<body>"
"Here is the text of my message."
"</body>"
;
"
\r\n
"
+
body
;
shared_ptr
<
const
Cpim
::
Message
>
message
=
Cpim
::
Message
::
createFromString
(
str
);
if
(
!
BC_ASSERT_PTR_NOT_NULL
(
message
))
return
;
const
string
str2
=
message
->
asString
();
BC_ASSERT_STRING_EQUAL
(
str2
.
c_str
(),
str
.
c_str
());
string
content
=
message
->
getContent
();
BC_ASSERT_STRING_EQUAL
(
content
.
c_str
(),
body
.
c_str
());
}
static
void
build_message
()
{
...
...
@@ -281,11 +291,11 @@ static void build_message () {
return
;
// Set CPIM headers.
Cpim
::
GenericHeader
contentTypeHeader
;
if
(
!
BC_ASSERT_TRUE
(
contentTypeHeader
.
setName
(
"Content-Type"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
contentTypeHeader
.
setValue
(
"Message/CPIM"
)))
return
;
Cpim
::
GenericHeader
c
pimC
ontentTypeHeader
;
if
(
!
BC_ASSERT_TRUE
(
c
pimC
ontentTypeHeader
.
setName
(
"Content-Type"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
c
pimC
ontentTypeHeader
.
setValue
(
"Message/CPIM"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
message
.
addCpimHeader
(
contentTypeHeader
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
message
.
addCpimHeader
(
c
pimC
ontentTypeHeader
)))
return
;
// Set message headers.
Cpim
::
FromHeader
fromHeader
;
...
...
@@ -328,10 +338,18 @@ static void build_message () {
if
(
!
BC_ASSERT_TRUE
(
message
.
addMessageHeader
(
vitalMessageHeader
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
message
.
addMessageHeader
(
wackyMessageHeader
)))
return
;
const
string
content
=
"Content-type text/xml; charset=utf-8
\r\n
"
"Content-ID: <1234567890@foo.com>
\r\n
"
"
\r\n
"
"<body>"
// Set Content headers.
Cpim
::
GenericHeader
contentTypeHeader
;
if
(
!
BC_ASSERT_TRUE
(
contentTypeHeader
.
setName
(
"Content-Type"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
contentTypeHeader
.
setValue
(
"text/xml; charset=utf-8"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
message
.
addContentHeader
(
contentTypeHeader
)))
return
;
Cpim
::
GenericHeader
contentIdHeader
;
if
(
!
BC_ASSERT_TRUE
(
contentIdHeader
.
setName
(
"Content-ID"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
contentIdHeader
.
setValue
(
"<1234567890@foo.com>"
)))
return
;
if
(
!
BC_ASSERT_TRUE
(
message
.
addContentHeader
(
contentIdHeader
)))
return
;
const
string
content
=
"<body>"
"Here is the text of my message."
"</body>"
;
...
...
@@ -351,7 +369,7 @@ static void build_message () {
"MyFeatures.VitalMessageOption: Confirmation-requested
\r\n
"
"MyFeatures.WackyMessageOption: Use-silly-font
\r\n
"
"
\r\n
"
"Content-
t
ype text/xml; charset=utf-8
\r\n
"
"Content-
T
ype
:
text/xml; charset=utf-8
\r\n
"
"Content-ID: <1234567890@foo.com>
\r\n
"
"
\r\n
"
"<body>"
...
...
@@ -361,6 +379,14 @@ static void build_message () {
BC_ASSERT_STRING_EQUAL
(
strMessage
.
c_str
(),
expectedMessage
.
c_str
());
}
static
void
cpim_chat_message_modifier_encoder
(
void
)
{
}
static
void
cpim_chat_message_modifier_decoder
(
void
)
{
}
test_t
cpim_tests
[]
=
{
TEST_NO_TAG
(
"Parse minimal CPIM message"
,
parse_minimal_message
),
TEST_NO_TAG
(
"Set generic header name"
,
set_generic_header_name
),
...
...
@@ -370,7 +396,9 @@ test_t cpim_tests[] = {
TEST_NO_TAG
(
"Check Subject header language"
,
check_subject_header_language
),
TEST_NO_TAG
(
"Parse RFC example"
,
parse_rfc_example
),
TEST_NO_TAG
(
"Parse Message with generic header parameters"
,
parse_message_with_generic_header_parameters
),
TEST_NO_TAG
(
"Build Message"
,
build_message
)
TEST_NO_TAG
(
"Build Message"
,
build_message
),
TEST_NO_TAG
(
"CPIM chat message modifier encoder"
,
cpim_chat_message_modifier_encoder
),
TEST_NO_TAG
(
"CPIM chat message modifier decoder"
,
cpim_chat_message_modifier_decoder
)
};
test_suite_t
cpim_test_suite
=
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment