20 #include "noteutils.h"
22 #include <klocalizedstring.h>
23 #include <kdatetime.h>
24 #include <kmime/kmime_message.h>
30 #include <QTextDocument>
35 #define X_NOTES_UID_HEADER "X-Akonotes-UID"
36 #define X_NOTES_LASTMODIFIED_HEADER "X-Akonotes-LastModified"
37 #define X_NOTES_CLASSIFICATION_HEADER "X-Akonotes-Classification"
38 #define X_NOTES_CUSTOM_HEADER "X-Akonotes-Custom"
40 #define CLASSIFICATION_PUBLIC "Public"
41 #define CLASSIFICATION_PRIVATE "Private"
42 #define CLASSIFICATION_CONFIDENTIAL "Confidential"
44 #define X_NOTES_URL_HEADER "X-Akonotes-Url"
45 #define X_NOTES_LABEL_HEADER "X-Akonotes-Label"
46 #define X_NOTES_CONTENTTYPE_HEADER "X-Akonotes-Type"
47 #define CONTENT_TYPE_CUSTOM "custom"
48 #define CONTENT_TYPE_ATTACHMENT "attachment"
50 #define ENCODING "utf-8"
52 class Attachment::AttachmentPrivate
55 AttachmentPrivate(
const QUrl&
url,
const QString&
mimetype )
60 AttachmentPrivate(
const QByteArray&
data,
const QString&
mimetype )
65 AttachmentPrivate(
const AttachmentPrivate &other )
77 : d_ptr( new
Attachment::AttachmentPrivate( url, mimetype ) )
82 : d_ptr( new
Attachment::AttachmentPrivate( data, mimetype ) )
87 : d_ptr(new AttachmentPrivate(*other.d_func()) )
92 Attachment::~Attachment()
97 bool Attachment::operator==(
const Attachment &a )
const
100 if ( d->mUrl.isEmpty() ) {
101 return d->mUrl == a.d_func()->mUrl &&
102 d->mMimetype == a.d_func()->mMimetype &&
103 d->mLabel == a.d_func()->mLabel;
105 return d->mData == a.d_func()->mData &&
106 d->mMimetype == a.d_func()->mMimetype &&
107 d->mLabel == a.d_func()->mLabel;
110 void Attachment::operator=(
const Attachment &a )
145 class NoteMessageWrapper::NoteMessageWrapperPrivate
148 NoteMessageWrapperPrivate()
153 NoteMessageWrapperPrivate(
const KMime::Message::Ptr &msg )
157 readMimeMessage(msg);
160 void readMimeMessage(
const KMime::Message::Ptr &msg );
162 KMime::Content* createCustomPart()
const;
163 void parseCustomPart( KMime::Content * );
165 KMime::Content* createAttachmentPart(
const Attachment & )
const;
166 void parseAttachmentPart( KMime::Content * );
174 QMap< QString, QString >
custom;
180 void NoteMessageWrapper::NoteMessageWrapperPrivate::readMimeMessage(
const KMime::Message::Ptr& msg)
183 kWarning() <<
"Empty message";
186 title = msg->subject(
true )->asUnicodeString();
187 text = msg->mainBodyPart()->decodedText(
true );
188 if ( msg->from(
false ) )
189 from = msg->from(
false )->asUnicodeString();
190 creationDate = msg->date(
true )->dateTime();
191 if ( msg->mainBodyPart()->contentType(
false ) && msg->mainBodyPart()->contentType()->mimeType() ==
"text/html" ) {
192 textFormat = Qt::RichText;
195 if (KMime::Headers::Base *lastmod = msg->headerByType(X_NOTES_LASTMODIFIED_HEADER)) {
196 const QByteArray &s = lastmod->asUnicodeString().toLatin1();
197 const char *cursor = s.constData();
198 if (!KMime::HeaderParsing::parseDateTime( cursor, cursor + s.length(), lastModifiedDate)) {
199 kWarning() <<
"failed to parse lastModifiedDate";
203 if (KMime::Headers::Base *uidHeader = msg->headerByType(X_NOTES_UID_HEADER)) {
204 uid = uidHeader->asUnicodeString();
207 if (KMime::Headers::Base *classificationHeader = msg->headerByType(X_NOTES_CLASSIFICATION_HEADER)) {
208 const QString &c = classificationHeader->asUnicodeString();
209 if ( c == CLASSIFICATION_PRIVATE ) {
210 classification = Private;
211 }
else if ( c == CLASSIFICATION_CONFIDENTIAL ) {
212 classification = Confidential;
216 const KMime::Content::List list = msg->contents();
217 Q_FOREACH(KMime::Content *c, msg->contents()) {
218 if (KMime::Headers::Base *typeHeader = c->headerByType(X_NOTES_CONTENTTYPE_HEADER)) {
219 const QString &type = typeHeader->asUnicodeString();
220 if ( type == CONTENT_TYPE_CUSTOM ) {
222 }
else if ( type == CONTENT_TYPE_ATTACHMENT ) {
223 parseAttachmentPart(c);
225 qWarning() <<
"unknown type " << type;
231 QDomDocument createXMLDocument()
233 QDomDocument document;
234 QString p =
"version=\"1.0\" encoding=\"UTF-8\"";
235 document.appendChild(document.createProcessingInstruction(
"xml", p ) );
239 QDomDocument loadDocument(KMime::Content *part)
242 int errorLine, errorColumn;
243 QDomDocument document;
244 bool ok = document.setContent( part->body(), &errorMsg, &errorLine, &errorColumn );
246 kWarning() << part->body();
247 qWarning(
"Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn );
248 return QDomDocument();
253 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createCustomPart()
const
255 KMime::Content* content =
new KMime::Content();
256 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_CUSTOM, ENCODING ) );
257 QDomDocument document = createXMLDocument();
258 QDomElement element = document.createElement(
"custom" );
259 element.setAttribute(
"version",
"1.0" );
260 for ( QMap <QString, QString >::const_iterator it = custom.begin(); it != custom.end(); ++it ) {
261 QDomElement e = element.ownerDocument().createElement( it.key() );
262 QDomText t = element.ownerDocument().createTextNode( it.value() );
264 element.appendChild( e );
265 document.appendChild( element );
267 content->setBody( document.toString().toLatin1() );
271 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseCustomPart( KMime::Content* part )
273 QDomDocument document = loadDocument( part );
274 if (document.isNull()) {
277 QDomElement top = document.documentElement();
278 if ( top.tagName() !=
"custom" ) {
279 qWarning(
"XML error: Top tag was %s instead of the expected custom",
280 top.tagName().toLatin1().data() );
284 for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
285 if ( n.isElement() ) {
286 QDomElement e = n.toElement();
287 custom.insert(e.tagName(), e.text());
289 kDebug() <<
"Node is not an element";
295 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createAttachmentPart(
const Attachment &a )
const
297 KMime::Content* content =
new KMime::Content();
298 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_ATTACHMENT, ENCODING ) );
299 if (a.url().isValid()) {
300 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_URL_HEADER, content, a.url().toString().toLatin1(), ENCODING ) );
302 content->setBody( a.data() );
304 content->contentType()->setMimeType( a.mimetype().toLatin1() );
305 if (!a.label().isEmpty()) {
306 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_LABEL_HEADER, content, a.label().toLatin1(), ENCODING ) );
308 content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
309 content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
310 content->contentDisposition()->setFilename(
"attachment" );
314 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseAttachmentPart( KMime::Content *part )
317 if ( KMime::Headers::Base *labelHeader = part->headerByType( X_NOTES_LABEL_HEADER ) ) {
318 label = labelHeader->asUnicodeString();
320 if ( KMime::Headers::Base *header = part->headerByType( X_NOTES_URL_HEADER ) ) {
321 Attachment attachment( QUrl( header->asUnicodeString() ), part->contentType()->mimeType() );
322 attachment.setLabel( label );
323 attachments.append(attachment);
325 Attachment attachment( part->decodedContent(), part->contentType()->mimeType() );
326 attachment.setLabel( label );
327 attachments.append(attachment);
331 NoteMessageWrapper::NoteMessageWrapper()
332 : d_ptr( new NoteMessageWrapperPrivate() )
336 NoteMessageWrapper::NoteMessageWrapper(
const KMime::Message::Ptr &msg )
337 : d_ptr( new NoteMessageWrapperPrivate(msg) )
341 NoteMessageWrapper::~NoteMessageWrapper()
349 KMime::Message::Ptr msg = KMime::Message::Ptr(
new KMime::Message() );
351 QString
title = i18nc(
"The default name for new notes.",
"New Note" );
352 if ( !d->title.isEmpty() ) {
356 QString
text = QLatin1String(
" ");
357 if ( !d->text.isEmpty() ) {
361 KDateTime
creationDate = KDateTime::currentLocalDateTime();
362 if ( d->creationDate.isValid() ) {
367 if ( d->lastModifiedDate.isValid() ) {
372 if ( !d->uid.isEmpty() ) {
375 uid = QUuid::createUuid();
378 msg->subject(
true )->fromUnicodeString(
title, ENCODING );
380 msg->from(
true )->fromUnicodeString( d->from, ENCODING );
381 msg->mainBodyPart()->fromUnicodeString(
text );
382 msg->mainBodyPart()->contentType(
true )->setMimeType( d->textFormat == Qt::RichText ?
"text/html" :
"text/plain" );
383 msg->appendHeader(
new KMime::Headers::Generic(X_NOTES_LASTMODIFIED_HEADER, msg.get(),
lastModifiedDate.toString( KDateTime::RFCDateDay ).toLatin1(), ENCODING ) );
384 msg->appendHeader(
new KMime::Headers::Generic( X_NOTES_UID_HEADER, msg.get(),
uid, ENCODING ) );
386 QString
classification = QString::fromLatin1(CLASSIFICATION_PUBLIC);
387 switch ( d->classification ) {
392 classification = QString::fromLatin1(CLASSIFICATION_CONFIDENTIAL);
398 msg->appendHeader(
new KMime::Headers::Generic( X_NOTES_CLASSIFICATION_HEADER, msg.get(),
classification, ENCODING ) );
400 foreach (
const Attachment &a, d->attachments) {
401 msg->addContent( d->createAttachmentPart(a) );
404 if ( !d->custom.isEmpty() ) {
405 msg->addContent( d->createCustomPart() );
433 return d->classification;
445 return d->lastModifiedDate;
457 return d->creationDate;
488 d->textFormat = format;
500 return d->textFormat;
506 if ( d->textFormat == Qt::PlainText ) {
511 QRegExp rx( QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive );
512 rx.indexIn( d->text );
513 QString body = rx.cap( 1 );
515 return Qt::escape( body.remove( QRegExp( QLatin1String(
"<[^>]*>") ) ).trimmed() );
521 return d->attachments;
530 QString noteIconName()
532 return QString::fromLatin1(
"text-plain" );
535 QString noteMimeType()
537 return QString::fromLatin1(
"text/x-vnd.akonadi.note" );