20 #include "noteutils.h"
22 #include <klocalizedstring.h>
23 #include <kdatetime.h>
24 #include <kmime/kmime_message.h>
34 #define X_NOTES_UID_HEADER "X-Akonotes-UID"
35 #define X_NOTES_LASTMODIFIED_HEADER "X-Akonotes-LastModified"
36 #define X_NOTES_CLASSIFICATION_HEADER "X-Akonotes-Classification"
37 #define X_NOTES_CUSTOM_HEADER "X-Akonotes-Custom"
39 #define CLASSIFICATION_PUBLIC "Public"
40 #define CLASSIFICATION_PRIVATE "Private"
41 #define CLASSIFICATION_CONFIDENTIAL "Confidential"
43 #define X_NOTES_URL_HEADER "X-Akonotes-Url"
44 #define X_NOTES_LABEL_HEADER "X-Akonotes-Label"
45 #define X_NOTES_CONTENTTYPE_HEADER "X-Akonotes-Type"
46 #define CONTENT_TYPE_CUSTOM "custom"
47 #define CONTENT_TYPE_ATTACHMENT "attachment"
49 #define ENCODING "utf-8"
51 class Attachment::AttachmentPrivate
54 AttachmentPrivate(
const QUrl&
url,
const QString&
mimetype )
59 AttachmentPrivate(
const QByteArray&
data,
const QString&
mimetype )
64 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()
98 bool Attachment::operator==(
const Attachment &a )
const
101 if ( d->mUrl.isEmpty() ) {
102 return d->mUrl == a.d_func()->mUrl &&
103 d->mMimetype == a.d_func()->mMimetype &&
104 d->mLabel == a.d_func()->mLabel;
106 return d->mData == a.d_func()->mData &&
107 d->mMimetype == a.d_func()->mMimetype &&
108 d->mLabel == a.d_func()->mLabel;
111 void Attachment::operator=(
const Attachment &a )
148 class NoteMessageWrapper::NoteMessageWrapperPrivate
151 NoteMessageWrapperPrivate()
156 NoteMessageWrapperPrivate(
const KMime::Message::Ptr &msg )
160 readMimeMessage(msg);
163 void readMimeMessage(
const KMime::Message::Ptr &msg );
165 KMime::Content* createCustomPart()
const;
166 void parseCustomPart( KMime::Content * );
168 KMime::Content* createAttachmentPart(
const Attachment & )
const;
169 void parseAttachmentPart( KMime::Content * );
178 QMap< QString, QString >
custom;
183 void NoteMessageWrapper::NoteMessageWrapperPrivate::readMimeMessage(
const KMime::Message::Ptr& msg)
186 kWarning() <<
"Empty message";
189 title = msg->subject(
true )->asUnicodeString();
190 text = msg->mainBodyPart()->decodedText(
true );
191 if ( msg->from(
false ) )
192 from = msg->from(
false )->asUnicodeString();
193 creationDate = msg->date(
true )->dateTime();
194 if ( msg->contentType(
false ) && msg->contentType(
false )->asUnicodeString() == QLatin1String(
"text/html") ) {
195 textFormat = Qt::RichText;
198 if (KMime::Headers::Base *lastmod = msg->headerByType(X_NOTES_LASTMODIFIED_HEADER)) {
199 const QByteArray &s = lastmod->asUnicodeString().toLatin1();
200 const char *cursor = s.constData();
201 if (!KMime::HeaderParsing::parseDateTime( cursor, cursor + s.length(), lastModifiedDate)) {
202 kWarning() <<
"failed to parse lastModifiedDate";
206 if (KMime::Headers::Base *uidHeader = msg->headerByType(X_NOTES_UID_HEADER)) {
207 uid = uidHeader->asUnicodeString();
210 if (KMime::Headers::Base *classificationHeader = msg->headerByType(X_NOTES_CLASSIFICATION_HEADER)) {
211 const QString &c = classificationHeader->asUnicodeString();
212 if ( c == CLASSIFICATION_PRIVATE ) {
213 classification = Private;
214 }
else if ( c == CLASSIFICATION_CONFIDENTIAL ) {
215 classification = Confidential;
219 const KMime::Content::List list = msg->contents();
220 Q_FOREACH(KMime::Content *c, msg->contents()) {
221 if (KMime::Headers::Base *typeHeader = c->headerByType(X_NOTES_CONTENTTYPE_HEADER)) {
222 const QString &type = typeHeader->asUnicodeString();
223 if ( type == CONTENT_TYPE_CUSTOM ) {
225 }
else if ( type == CONTENT_TYPE_ATTACHMENT ) {
226 parseAttachmentPart(c);
228 qWarning() <<
"unknown type " << type;
234 QDomDocument createXMLDocument()
236 QDomDocument document;
237 QString p =
"version=\"1.0\" encoding=\"UTF-8\"";
238 document.appendChild(document.createProcessingInstruction(
"xml", p ) );
242 QDomDocument loadDocument(KMime::Content *part)
245 int errorLine, errorColumn;
246 QDomDocument document;
247 bool ok = document.setContent( part->body(), &errorMsg, &errorLine, &errorColumn );
249 kWarning() << part->body();
250 qWarning(
"Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn );
251 return QDomDocument();
256 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createCustomPart()
const
258 KMime::Content* content =
new KMime::Content();
259 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_CUSTOM, ENCODING ) );
260 QDomDocument document = createXMLDocument();
261 QDomElement element = document.createElement(
"custom" );
262 element.setAttribute(
"version",
"1.0" );
263 for ( QMap <QString, QString >::const_iterator it = custom.begin(); it != custom.end(); ++it ) {
264 QDomElement e = element.ownerDocument().createElement( it.key() );
265 QDomText t = element.ownerDocument().createTextNode( it.value() );
267 element.appendChild( e );
268 document.appendChild( element );
270 content->setBody( document.toString().toLatin1() );
274 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseCustomPart( KMime::Content* part )
276 QDomDocument document = loadDocument( part );
277 if (document.isNull()) {
280 QDomElement top = document.documentElement();
281 if ( top.tagName() !=
"custom" ) {
282 qWarning(
"XML error: Top tag was %s instead of the expected custom",
283 top.tagName().toLatin1().data() );
287 for ( QDomNode n = top.firstChild(); !n.isNull(); n = n.nextSibling() ) {
288 if ( n.isElement() ) {
289 QDomElement e = n.toElement();
290 custom.insert(e.tagName(), e.text());
292 kDebug() <<
"Node is not an element";
298 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createAttachmentPart(
const Attachment &a )
const
300 KMime::Content* content =
new KMime::Content();
301 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_CONTENTTYPE_HEADER, content, CONTENT_TYPE_ATTACHMENT, ENCODING ) );
302 if (a.url().isValid()) {
303 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_URL_HEADER, content, a.url().toString().toLatin1(), ENCODING ) );
305 content->setBody( a.data() );
307 content->contentType()->setMimeType( a.mimetype().toLatin1() );
308 if (!a.label().isEmpty()) {
309 content->appendHeader(
new KMime::Headers::Generic( X_NOTES_LABEL_HEADER, content, a.label().toLatin1(), ENCODING ) );
311 content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
312 content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
313 content->contentDisposition()->setFilename(
"attachment" );
317 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseAttachmentPart( KMime::Content *part )
320 if ( KMime::Headers::Base *labelHeader = part->headerByType( X_NOTES_LABEL_HEADER ) ) {
321 label = labelHeader->asUnicodeString();
323 if ( KMime::Headers::Base *header = part->headerByType( X_NOTES_URL_HEADER ) ) {
324 Attachment attachment( QUrl( header->asUnicodeString() ), part->contentType()->mimeType() );
325 attachment.setLabel( label );
326 attachments.append(attachment);
328 Attachment attachment( part->decodedContent(), part->contentType()->mimeType() );
329 attachment.setLabel( label );
330 attachments.append(attachment);
334 NoteMessageWrapper::NoteMessageWrapper()
335 : d_ptr( new NoteMessageWrapperPrivate() )
339 NoteMessageWrapper::NoteMessageWrapper(
const KMime::Message::Ptr &msg )
340 : d_ptr( new NoteMessageWrapperPrivate(msg) )
344 NoteMessageWrapper::~NoteMessageWrapper()
352 KMime::Message::Ptr msg = KMime::Message::Ptr(
new KMime::Message() );
354 QString
title = i18nc(
"The default name for new notes.",
"New Note" );
355 if ( !d->title.isEmpty() ) {
359 QString
text = QLatin1String(
" ");
360 if ( !d->text.isEmpty() ) {
364 KDateTime
creationDate = KDateTime::currentLocalDateTime();
365 if ( d->creationDate.isValid() ) {
366 creationDate = d->creationDate;
370 if ( d->lastModifiedDate.isValid() ) {
371 lastModifiedDate = d->lastModifiedDate;
375 if ( !d->uid.isEmpty() ) {
378 uid = QUuid::createUuid();
381 msg->subject(
true )->fromUnicodeString( title, ENCODING );
382 msg->contentType(
true )->setMimeType( d->textFormat == Qt::RichText ?
"text/html" :
"text/plain" );
383 msg->date(
true )->setDateTime( creationDate );
384 msg->from(
true )->fromUnicodeString( d->from, ENCODING );
385 msg->mainBodyPart()->fromUnicodeString( text );
386 msg->appendHeader(
new KMime::Headers::Generic(X_NOTES_LASTMODIFIED_HEADER, msg.get(), lastModifiedDate.toString( KDateTime::RFCDateDay ).toLatin1(), ENCODING ) );
387 msg->appendHeader(
new KMime::Headers::Generic( X_NOTES_UID_HEADER, msg.get(),
uid, ENCODING ) );
389 QString
classification = QString::fromLatin1(CLASSIFICATION_PUBLIC);
390 switch ( d->classification ) {
392 classification = QString::fromLatin1(CLASSIFICATION_PRIVATE);
395 classification = QString::fromLatin1(CLASSIFICATION_CONFIDENTIAL);
401 msg->appendHeader(
new KMime::Headers::Generic( X_NOTES_CLASSIFICATION_HEADER, msg.get(),
classification, ENCODING ) );
403 foreach (
const Attachment &a, d->attachments) {
404 msg->addContent( d->createAttachmentPart(a) );
407 if ( !d->custom.isEmpty() ) {
408 msg->addContent( d->createCustomPart() );
436 return d->classification;
448 return d->lastModifiedDate;
460 return d->creationDate;
491 d->textFormat = format;
503 return d->textFormat;
509 if ( d->textFormat == Qt::PlainText ) {
514 QRegExp rx( QLatin1String(
"<body[^>]*>(.*)</body>"), Qt::CaseInsensitive );
515 rx.indexIn( d->text );
516 QString body = rx.cap( 1 );
518 return Qt::escape( body.remove( QRegExp( QLatin1String(
"<[^>]*>") ) ).trimmed() );
524 return d->attachments;
535 QString noteIconName()
537 return QString::fromLatin1(
"text-plain" );
540 QString noteMimeType()
542 return QString::fromLatin1(
"text/x-vnd.akonadi.note" );