Merge lp:~davidagraf/zorba/email-module-fixes into lp:zorba/email-module
- email-module-fixes
- Merge into email-module
Status: | Merged |
---|---|
Approved by: | David Graf |
Approved revision: | 47 |
Merged at revision: | 47 |
Proposed branch: | lp:~davidagraf/zorba/email-module-fixes |
Merge into: | lp:zorba/email-module |
Diff against target: |
496 lines (+151/-87) 2 files modified
src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp (+148/-85) src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h (+3/-2) |
To merge this branch: | bzr merge lp:~davidagraf/zorba/email-module-fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Graf (community) | Approve | ||
Dennis Knochenwefel | Approve | ||
Alexander Kreutz (community) | Approve | ||
Review via email: mp+112051@code.launchpad.net |
Commit message
Several email module fixes:
- case insensitive email attribute comparison
- catch more attachment filenames
- don't create empty recipients and email tags
- fixed typos
- made constant for namespace prefix
- introduced default mime charset
- remove newlines from base64 that comes from uw-imap
- if email content is quoted-printable encoded and the content type binary, it needs to be encoded into base64
- fixed content type check
- decode all email headers
- non-ascii (non encoded) chars are not allowed in email headers -> we ignore them
- added missing namespaces
Description of the change
Several email module fixes:
- case insensitive email attribute comparison
- catch more attachment filenames
- don't create empty recipients and email tags
- fixed typos
- made constant for namespace prefix
- introduced default mime charset
- remove newlines from base64 that comes from uw-imap
- if email content is quoted-printable encoded and the content type binary, it needs to be encoded into base64
- fixed content type check
- decode all email headers
- non-ascii (non encoded) chars are not allowed in email headers -> we ignore them
- added missing namespaces
Alexander Kreutz (kreutz) : | # |
David Graf (davidagraf) : | # |
David Graf (davidagraf) wrote : | # |
David Graf (davidagraf) : | # |
Dennis Knochenwefel (dennis-knochenwefel) : | # |
David Graf (davidagraf) wrote : | # |
The failing query execution on ubuntu has nothing to do with this change. When execution in a different environment, it works. Therefore, I approve it.
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for merge proposal.
Log at: http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue job email-module-
All tests succeeded!
Preview Diff
1 | === modified file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp' |
2 | --- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp 2012-06-01 13:35:25 +0000 |
3 | +++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.cpp 2012-06-26 10:10:34 +0000 |
4 | @@ -21,10 +21,11 @@ |
5 | #include <map> |
6 | #include <sstream> |
7 | |
8 | -#include <zorba/zorba.h> |
9 | +#include <zorba/base64.h> |
10 | +#include <zorba/diagnostic_list.h> |
11 | #include <zorba/iterator.h> |
12 | #include <zorba/user_exception.h> |
13 | -#include <zorba/diagnostic_list.h> |
14 | +#include <zorba/zorba.h> |
15 | |
16 | #include <unicode/ucnv.h> |
17 | #include <unicode/ustring.h> |
18 | @@ -36,6 +37,7 @@ |
19 | namespace zorba { namespace emailmodule { |
20 | |
21 | const char* ImapFunction::SCHEMA_NAMESPACE = "http://www.zorba-xquery.com/modules/email"; |
22 | +const char* ImapFunction::SCHEMA_PREFIX = "email"; |
23 | |
24 | ImapFunction::ImapFunction(const ImapModule* aModule) |
25 | : theModule(aModule) |
26 | @@ -297,11 +299,11 @@ |
27 | const bool aQualified) const |
28 | { |
29 | NsBindings ns_binding; |
30 | - ns_binding.push_back(std::pair<String, String>("email", SCHEMA_NAMESPACE)); |
31 | + ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE)); |
32 | |
33 | // if aParent is null, then we want to have the flags node qualified (so that it can be shema validated) |
34 | Item lFlagsName; |
35 | - lFlagsName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "flags"); |
36 | + lFlagsName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "flags"); |
37 | Item lFlagsType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "flagsType"); |
38 | aFlags = theModule->getItemFactory()->createElementNode(aParent, lFlagsName, lFlagsType, false, false, ns_binding); |
39 | |
40 | @@ -327,7 +329,7 @@ |
41 | break; |
42 | } |
43 | |
44 | - Item lOneFlagName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", lFlagName); |
45 | + Item lOneFlagName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, lFlagName); |
46 | Item lOneFlagType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "emptyType"); |
47 | Item lOneFlag = theModule->getItemFactory()->createElementNode(aFlags, lOneFlagName, lOneFlagType, false, true, ns_binding); |
48 | } |
49 | @@ -366,7 +368,7 @@ |
50 | Item lNullItem; |
51 | |
52 | NsBindings null_binding; |
53 | - Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "content"); |
54 | + Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "content"); |
55 | Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "contentType" ); |
56 | Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, null_binding); |
57 | |
58 | @@ -390,37 +392,51 @@ |
59 | const char* aMailbox, |
60 | const char* aHost) const |
61 | { |
62 | - Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "emailAddress"); |
63 | - Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", aName); |
64 | - |
65 | - NsBindings ns_binding; |
66 | - ns_binding.push_back(std::pair<String, String>("email", SCHEMA_NAMESPACE)); |
67 | - |
68 | - Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding); |
69 | - if (aPersonal) { |
70 | - createInnerNodeWithText(lItem, SCHEMA_NAMESPACE, "email", "name", "http://www.w3.org/2001/XMLSchema", "string", aPersonal); |
71 | - } |
72 | if ((aMailbox) && (aHost)) { |
73 | - createInnerNodeWithText(lItem, SCHEMA_NAMESPACE, "email", "email", SCHEMA_NAMESPACE, "emailAddressType", std::string(aMailbox) + "@" + std::string(aHost)); |
74 | + // mailbox and host needs to be available, otherwise broken |
75 | + Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "emailAddress"); |
76 | + Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, aName); |
77 | + |
78 | + NsBindings ns_binding; |
79 | + ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE)); |
80 | + |
81 | + Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding); |
82 | + if (aPersonal) { |
83 | + std::string lDecodedPersonal; |
84 | + decodeHeader(std::string(aPersonal), lDecodedPersonal); |
85 | + createInnerNodeWithText( |
86 | + lItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "name", |
87 | + "http://www.w3.org/2001/XMLSchema", "string", lDecodedPersonal); |
88 | + } |
89 | + |
90 | + std::string lDecodedMailbox, lDecodedHost; |
91 | + decodeHeader(std::string(aMailbox), lDecodedMailbox); |
92 | + decodeHeader(std::string(aHost), lDecodedHost); |
93 | + createInnerNodeWithText( |
94 | + lItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "email", SCHEMA_NAMESPACE, |
95 | + "emailAddressType", lDecodedMailbox + "@" + lDecodedHost); |
96 | } |
97 | } |
98 | |
99 | void |
100 | -ImapFunction::createRecipentNode( |
101 | +ImapFunction::createRecipientNode( |
102 | Item& aParent, |
103 | const std::string& aName, |
104 | const char* aPersonal, |
105 | const char* aMailbox, |
106 | const char* aHost) const |
107 | { |
108 | - Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "recipientType"); |
109 | - Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "recipient"); |
110 | - |
111 | - NsBindings ns_binding; |
112 | - ns_binding.push_back(std::pair<String, String>("email", SCHEMA_NAMESPACE)); |
113 | - |
114 | - Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding); |
115 | - createEmailAddressNode(lItem, aName, aPersonal, aMailbox, aHost); |
116 | + if (aMailbox && aHost) { |
117 | + // mailbox and host needs to be available, otherwise bcc |
118 | + Item lType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "recipientType"); |
119 | + Item lName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "recipient"); |
120 | + |
121 | + NsBindings ns_binding; |
122 | + ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE)); |
123 | + |
124 | + Item lItem = theModule->getItemFactory()->createElementNode(aParent, lName, lType, false, false, ns_binding); |
125 | + createEmailAddressNode(lItem, aName, aPersonal, aMailbox, aHost); |
126 | + } |
127 | } |
128 | |
129 | void |
130 | @@ -499,7 +515,7 @@ |
131 | } |
132 | |
133 | NsBindings ns_binding; |
134 | - ns_binding.push_back(std::pair<String, String>("email", SCHEMA_NAMESPACE)); |
135 | + ns_binding.push_back(std::pair<String, String>(SCHEMA_PREFIX, SCHEMA_NAMESPACE)); |
136 | |
137 | Item lEnvelopeItem; |
138 | std::string lErrorMessage = ImapClient::Instance().getError(); |
139 | @@ -512,33 +528,37 @@ |
140 | // Important: if we only want the envelope, then the envelope MUST be qualified (being the root of the DOM) |
141 | Item lEnvelopeName; |
142 | if (aOnlyEnvelope) { |
143 | - lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "envelope"); |
144 | + lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelope"); |
145 | } else { |
146 | - lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "envelope"); |
147 | + lEnvelopeName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelope"); |
148 | } |
149 | - Item lEnvelopeType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "envelopeType"); |
150 | + Item lEnvelopeType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "envelopeType"); |
151 | |
152 | Item lNullItem; |
153 | // if we only want the envelope, then create it with a null parent, else create the message and use it as parent |
154 | if (aOnlyEnvelope) { |
155 | lEnvelopeItem = theModule->getItemFactory()->createElementNode(lNullItem, lEnvelopeName, lEnvelopeType, false, false, ns_binding); |
156 | } else { |
157 | - Item lMessageName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "message"); |
158 | - Item lMessageType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "messageType"); |
159 | + Item lMessageName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "message"); |
160 | + Item lMessageType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "messageType"); |
161 | aParent = theModule->getItemFactory()->createElementNode(lNullItem, lMessageName, lMessageType, false, false, ns_binding); |
162 | lEnvelopeItem = theModule->getItemFactory()->createElementNode(aParent, lEnvelopeName, lEnvelopeType, false, false, ns_binding); |
163 | } |
164 | |
165 | // create the remail node if needed |
166 | if (lEnvelope->remail) { |
167 | - createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, "email", "remail", "http://www.w3.org/2001/XMLSchema", "string", lEnvelope->remail); |
168 | + std::string lDecodedRemail; |
169 | + decodeHeader(std::string(lEnvelope->remail), lDecodedRemail); |
170 | + createInnerNodeWithText( |
171 | + lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "remail", |
172 | + "http://www.w3.org/2001/XMLSchema", "string", lDecodedRemail); |
173 | } |
174 | // create the date node if needed |
175 | if (lEnvelope->date) { |
176 | createInnerNodeWithText( |
177 | lEnvelopeItem, |
178 | SCHEMA_NAMESPACE, |
179 | - "email", |
180 | + SCHEMA_PREFIX, |
181 | "date", |
182 | "http://www.w3.org/2001/XMLSchema", |
183 | "string", |
184 | @@ -561,36 +581,36 @@ |
185 | std::string lSubject = lEnvelope->subject; |
186 | std::string lDecodedSubject; |
187 | decodeHeader(lSubject, lDecodedSubject); |
188 | - createInnerNodeWithText(lEnvelopeItem, "", "", "subject", "http://www.w3.org/2001/XMLSchema", "string", lDecodedSubject); |
189 | + createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "subject", "http://www.w3.org/2001/XMLSchema", "string", lDecodedSubject); |
190 | } |
191 | |
192 | - ADDRESS* lRecipents; |
193 | + ADDRESS* lRecipients; |
194 | if (lEnvelope->to) { |
195 | - createRecipentNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host); |
196 | - lRecipents = lEnvelope->to; |
197 | - while ((lRecipents = lRecipents->next)) { |
198 | - createRecipentNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host); |
199 | + createRecipientNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host); |
200 | + lRecipients = lEnvelope->to; |
201 | + while ((lRecipients = lRecipients->next)) { |
202 | + createRecipientNode(lEnvelopeItem, "to", lEnvelope->to->personal, lEnvelope->to->mailbox, lEnvelope->to->host); |
203 | } |
204 | } |
205 | |
206 | if (lEnvelope->cc) { |
207 | - createRecipentNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host); |
208 | - lRecipents = lEnvelope->cc; |
209 | - while ((lRecipents = lRecipents->next)) { |
210 | - createRecipentNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host); |
211 | + createRecipientNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host); |
212 | + lRecipients = lEnvelope->cc; |
213 | + while ((lRecipients = lRecipients->next)) { |
214 | + createRecipientNode(lEnvelopeItem, "cc", lEnvelope->cc->personal, lEnvelope->cc->mailbox, lEnvelope->cc->host); |
215 | } |
216 | } |
217 | |
218 | - if ((lRecipents = lEnvelope->bcc)) { |
219 | - createRecipentNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host); |
220 | - while ((lRecipents = lRecipents->next)) { |
221 | - createRecipentNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host); |
222 | + if ((lRecipients = lEnvelope->bcc)) { |
223 | + createRecipientNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host); |
224 | + while ((lRecipients = lRecipients->next)) { |
225 | + createRecipientNode(lEnvelopeItem, "bcc", lEnvelope->bcc->personal, lEnvelope->bcc->mailbox, lEnvelope->bcc->host); |
226 | } |
227 | } |
228 | |
229 | // create messageId node |
230 | if (lEnvelope->message_id) { |
231 | - createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, "email", "messageId", "http://www.w3.org/2001/XMLSchema", "string", lEnvelope->message_id); |
232 | + createInnerNodeWithText(lEnvelopeItem, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "messageId", "http://www.w3.org/2001/XMLSchema", "string", lEnvelope->message_id); |
233 | } |
234 | Item lFlagsItem; |
235 | // create flags node |
236 | @@ -605,20 +625,20 @@ |
237 | // if we want the whole message, then build it together |
238 | |
239 | // <email:mimeVersion>1.0</email:mimeVersion> |
240 | - createInnerNodeWithText(aParent, SCHEMA_NAMESPACE, "email", "mimeVersion", "http://www.w3.org/2001/XMLSchema", "string", "1.0"); |
241 | + createInnerNodeWithText(aParent, SCHEMA_NAMESPACE, SCHEMA_PREFIX, "mimeVersion", "http://www.w3.org/2001/XMLSchema", "string", "1.0"); |
242 | |
243 | // make a tolower version of the subtype |
244 | std::string lSubType(lBody->subtype); |
245 | std::transform(lSubType.begin(), lSubType.end(), lSubType.begin(), tolower); |
246 | |
247 | // creating the <body> node |
248 | - Item lBodyName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "body"); |
249 | - Item lBodyType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "bodyTypeChoice"); |
250 | + Item lBodyName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "body"); |
251 | + Item lBodyType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "bodyTypeChoice"); |
252 | Item lBodyItem = theModule->getItemFactory()->createElementNode(aParent, lBodyName, lBodyType, false, false, ns_binding); |
253 | // in case of non-multipart, just add the body to the message |
254 | |
255 | - Item lMultipartParentName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "multipart"); |
256 | - Item lMultipartParentType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, "email", "multipartType"); |
257 | + Item lMultipartParentName = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "multipart"); |
258 | + Item lMultipartParentType = theModule->getItemFactory()->createQName(SCHEMA_NAMESPACE, SCHEMA_PREFIX, "multipartType"); |
259 | Item lMultipartParent; |
260 | // using a vector instead of a stack, because including stack will clash with the c-client include ... |
261 | std::vector<BODY*> lBodies; |
262 | @@ -656,10 +676,15 @@ |
263 | |
264 | PARAMETER* lCurrentParameter = lCurrentBody->disposition.parameter; |
265 | while (lCurrentParameter != NIL) { |
266 | - |
267 | - if (!std::string("filename").compare(lCurrentParameter->attribute)) { |
268 | - lContentDispositionFilename = cpystr(lCurrentParameter->value); |
269 | - } else if (!std::string("modification-date").compare(lCurrentParameter->attribute)) { |
270 | + std::string lAttribute = lCurrentParameter->attribute; |
271 | + std::transform(lAttribute.begin(), lAttribute.end(), lAttribute.begin(), ::tolower); |
272 | + if (!std::string("filename").compare(lAttribute)) { |
273 | + lContentDispositionFilename = cpystr(lCurrentParameter->value); |
274 | + } else if (!std::string("filename*0").compare(lAttribute)) { |
275 | + // TODO this is a hack that works for most cases. |
276 | + // See: http://tools.ietf.org/html/rfc2184 [Page 3] |
277 | + lContentDispositionFilename = cpystr(lCurrentParameter->value); |
278 | + } else if (!std::string("modification-date").compare(lAttribute)) { |
279 | lContentDispositionModificationDate = cpystr(lCurrentParameter->value); |
280 | } |
281 | |
282 | @@ -684,10 +709,14 @@ |
283 | std::string lBodyContent = ImapClient::Instance().fetchBodyFull(aHostName, aUserName, aPassword, aMailbox, aMessageNumber, lNoMultipart ? "1" : lCurrentSection, aUid); |
284 | |
285 | // reading charset from email |
286 | - const char* lCharset = 0; |
287 | + // default mime charset, see |
288 | + // http://tools.ietf.org/html/draft-ietf-appsawg-mime-default-charset-04 |
289 | + std::string lCharset = "ISO-8859-1"; |
290 | PARAMETER* lParam = lCurrentBody->parameter; |
291 | while (lParam) { |
292 | - if (strcmp(lParam->attribute, "charset") == 0) { |
293 | + std::string lAttribute = lParam->attribute; |
294 | + std::transform(lAttribute.begin(), lAttribute.end(), lAttribute.begin(), ::tolower); |
295 | + if (lAttribute.compare("charset") == 0) { |
296 | lCharset = lParam->value; |
297 | } |
298 | lParam = lParam->next; |
299 | @@ -697,7 +726,7 @@ |
300 | unsigned short lEncoding = lCurrentBody->encoding; |
301 | // decode the body according the transfer encoding if it is quoted-printable |
302 | decodeTextualTransferEncoding(lBodyContent, lContentType, lEncoding, lTransferEncodingDecoded); |
303 | - |
304 | + |
305 | // decode the body according to the charset |
306 | std::string lCharsetDecoded; |
307 | toUtf8(lTransferEncodingDecoded, lCharset, lCharsetDecoded); |
308 | @@ -736,10 +765,10 @@ |
309 | void |
310 | ImapFunction::toUtf8( |
311 | const std::string& aValue, |
312 | - const char* aFromCharset, |
313 | + const std::string& aFromCharset, |
314 | std::string& aResult) const |
315 | { |
316 | - if (!aFromCharset || std::string(aFromCharset) == "") { |
317 | + if (aFromCharset == "") { |
318 | aResult = aValue; |
319 | return; |
320 | } |
321 | @@ -752,7 +781,7 @@ |
322 | UConverter *lConverter; |
323 | |
324 | // set up the converter |
325 | - lConverter = ucnv_open(aFromCharset, &lStatus); |
326 | + lConverter = ucnv_open(aFromCharset.c_str(), &lStatus); |
327 | checkStatus(lStatus); |
328 | |
329 | // convert to Unicode |
330 | @@ -793,23 +822,42 @@ |
331 | } |
332 | } |
333 | |
334 | +struct PrintableAsciiChar |
335 | +{ |
336 | + bool operator()(char c) const { |
337 | + unsigned int u = static_cast<unsigned int>(c); |
338 | + return !(u == '\t' || u == '\n' || u == '\t' || (u >= 32 && u <= 127)); |
339 | + } |
340 | +}; |
341 | |
342 | void |
343 | ImapFunction::decodeHeader( |
344 | const std::string& aValue, |
345 | std::string& aResult) const |
346 | { |
347 | + std::string lValue = aValue; |
348 | + // We assume that email headers must not contain non-printable characters |
349 | + // because special chars need to be encoded. |
350 | + // Therefore, we filter everything non-printable out to avoid problems. |
351 | + lValue.erase( |
352 | + std::remove_if( |
353 | + lValue.begin(), |
354 | + lValue.end(), |
355 | + PrintableAsciiChar()), |
356 | + lValue.end() |
357 | + ); |
358 | + |
359 | std::stringstream lDecoded; |
360 | std::size_t lMarker = 0; |
361 | |
362 | // size used many times |
363 | - std::size_t lLength = aValue.length(); |
364 | + std::size_t lLength = lValue.length(); |
365 | // to collect question mark positions |
366 | std::vector<std::size_t> lQMs; |
367 | |
368 | // populate the above vectors |
369 | for (std::size_t i = 0; i < lLength; i++) { |
370 | - if (aValue.at(i) == '?') { |
371 | + if (lValue.at(i) == '?') { |
372 | lQMs.push_back(i); |
373 | } |
374 | } |
375 | @@ -819,7 +867,7 @@ |
376 | |
377 | // not enough questions marks to make up an encoding, give up |
378 | if (lQLength < 4) { |
379 | - aResult = aValue; |
380 | + aResult = lValue; |
381 | return; |
382 | } |
383 | |
384 | @@ -830,17 +878,17 @@ |
385 | // 2nd and 3rd question marks have only one character in between |
386 | lQMs[j + 1] + 2 == lQMs[j + 2] && |
387 | // 1st question mark is prefixed by an equal sign |
388 | - (lQMs[j] > 0 && aValue.at(lQMs[j] - 1) == '=') && |
389 | + (lQMs[j] > 0 && lValue.at(lQMs[j] - 1) == '=') && |
390 | // 4th question mark is suffixes by an equal sign |
391 | - (lQMs[j + 3] < (lLength-1) && aValue.at(lQMs[j + 3] + 1) == '=')) |
392 | + (lQMs[j + 3] < (lLength-1) && lValue.at(lQMs[j + 3] + 1) == '=')) |
393 | { |
394 | // ok were good, so first save the text from the last marker |
395 | // upto the starting equal sign |
396 | - lDecoded << aValue.substr(lMarker, lQMs[j] - lMarker - 1); |
397 | + lDecoded << lValue.substr(lMarker, lQMs[j] - lMarker - 1); |
398 | |
399 | // then take the entire region, including =? and ?= and try to decode it |
400 | std::string lWords; |
401 | - decodeEncodedWords(aValue.substr(lQMs[j] - 1, lQMs[j + 3] - lQMs[j] + 3), lWords); |
402 | + decodeEncodedWords(lValue.substr(lQMs[j] - 1, lQMs[j + 3] - lQMs[j] + 3), lWords); |
403 | lDecoded << lWords; |
404 | |
405 | // save the new marker at the end of this encoded word group |
406 | @@ -854,11 +902,16 @@ |
407 | ++j; |
408 | } |
409 | } |
410 | - lDecoded << aValue.substr(lMarker); |
411 | + lDecoded << lValue.substr(lMarker); |
412 | |
413 | aResult = lDecoded.str(); |
414 | } |
415 | |
416 | +bool isTextOrXMLContentType(const std::string& aContentType) { |
417 | + return aContentType.find("text/") != std::string::npos |
418 | + || aContentType == "application/xml" |
419 | + || aContentType.find("+xml") != std::string::npos; |
420 | +} |
421 | |
422 | void |
423 | ImapFunction::decodeTextualTransferEncoding( |
424 | @@ -873,19 +926,29 @@ |
425 | aResult = std::string((char *)lNewData, lNewLength); |
426 | fs_give(&lNewData); |
427 | aEncoding = ENC8BIT; |
428 | - } |
429 | - else if (aEncoding == ENCBASE64 && |
430 | - ( |
431 | - aContentType.find("text") != std::string::npos |
432 | - || aContentType.find("xml") != std::string::npos |
433 | - )) { |
434 | - unsigned long lNewLength; |
435 | - void* lNewData = rfc822_base64((unsigned char*)aValue.c_str(), aValue.length(), &lNewLength); |
436 | - aResult = std::string((char *)lNewData, lNewLength); |
437 | - fs_give(&lNewData); |
438 | - aEncoding = ENC8BIT; |
439 | - } |
440 | - else { |
441 | + if (!isTextOrXMLContentType(aContentType)) { |
442 | + // binary content needs to be base64 encoded for zorba |
443 | + zorba::String lInput(aResult.c_str()); |
444 | + zorba::String lOutput = zorba::encoding::Base64::encode(lInput); |
445 | + aResult = lOutput.c_str(); |
446 | + } |
447 | + } |
448 | + else if (aEncoding == ENCBASE64) { |
449 | + aResult = aValue; |
450 | + // remove newlines from base64 |
451 | + aResult.erase(std::remove(aResult.begin(), aResult.end(), '\r'), aResult.end()); |
452 | + aResult.erase(std::remove(aResult.begin(), aResult.end(), '\n'), aResult.end()); |
453 | + if (isTextOrXMLContentType(aContentType)) |
454 | + { |
455 | + unsigned long lNewLength; |
456 | + void* lNewData = rfc822_base64((unsigned char*)aResult.c_str(), aResult.length(), &lNewLength); |
457 | + aResult = std::string((char *)lNewData, lNewLength); |
458 | + fs_give(&lNewData); |
459 | + aEncoding = ENC8BIT; |
460 | + } |
461 | + } |
462 | + else |
463 | + { |
464 | aResult = aValue; |
465 | } |
466 | } |
467 | |
468 | === modified file 'src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h' |
469 | --- src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h 2012-01-11 16:52:34 +0000 |
470 | +++ src/com/zorba-xquery/www/modules/email/imap.xq.src/imap_function.h 2012-06-26 10:10:34 +0000 |
471 | @@ -35,6 +35,7 @@ |
472 | protected: |
473 | const ImapModule* theModule; |
474 | static const char* SCHEMA_NAMESPACE; |
475 | + static const char* SCHEMA_PREFIX; |
476 | |
477 | void |
478 | raiseImapError( |
479 | @@ -130,7 +131,7 @@ |
480 | const char* aHost) const; |
481 | |
482 | void |
483 | - createRecipentNode( |
484 | + createRecipientNode( |
485 | Item& aParent, |
486 | const std::string& aName, |
487 | const char* aPersonal, |
488 | @@ -167,7 +168,7 @@ |
489 | void |
490 | toUtf8( |
491 | const std::string& value, |
492 | - const char* fromCharset, |
493 | + const std::string& fromCharset, |
494 | std::string& result) const; |
495 | |
496 | void |
Unfortunately, I cannot run fix on ubuntu 12.04 because of:
./bin/zorba -q ~/sausalito/ build/test. xq -f dagraf/ zorba/build/ LIB_PATH/ com/zorba- xquery/ www/modules/ email/libsmtp_ 1.0.so" : error loading dynamic library: /home/dagraf/ zorba/build/ LIB_PATH/ com/zorba- xquery/ www/modules/ email/libsmtp_ 1.0.so: undefined symbol: crypt; raised at /home/dagraf/ zorba/sandbox/ src/context/ dynamic_ loader. cpp:168
operating system error [zerr:ZOSE0005]: "/home/
But it has nothing to do with the change.