• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
  • notes
noteutils.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2011 Christian Mollekopf <chrigi_1@fastmail.fm>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "noteutils.h"
21 
22 #include <klocalizedstring.h>
23 #include <kdatetime.h>
24 #include <kmime/kmime_message.h>
25 #include <kdebug.h>
26 
27 #include <qstring.h>
28 #include <quuid.h>
29 #include <qdom.h>
30 
31 namespace Akonadi {
32 namespace NoteUtils {
33 
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"
38 
39 #define CLASSIFICATION_PUBLIC "Public"
40 #define CLASSIFICATION_PRIVATE "Private"
41 #define CLASSIFICATION_CONFIDENTIAL "Confidential"
42 
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"
48 
49 #define ENCODING "utf-8"
50 
51 class Attachment::AttachmentPrivate
52 {
53  public:
54  AttachmentPrivate( const QUrl& url, const QString& mimetype )
55  : mUrl( url ),
56  mMimetype( mimetype )
57  {}
58 
59  AttachmentPrivate( const QByteArray& data, const QString& mimetype )
60  : mData( data ),
61  mMimetype( mimetype )
62  {}
63 
64  AttachmentPrivate( const AttachmentPrivate &other )
65  {
66  *this = other;
67  }
68 
69  QUrl mUrl;
70  QByteArray mData;
71  QString mMimetype;
72  QString mLabel;
73 };
74 
75 
76 Attachment::Attachment( const QUrl& url, const QString& mimetype )
77 : d_ptr( new Attachment::AttachmentPrivate( url, mimetype ) )
78 {
79 }
80 
81 Attachment::Attachment( const QByteArray& data, const QString& mimetype )
82 : d_ptr( new Attachment::AttachmentPrivate( data, mimetype ) )
83 {
84 }
85 
86 Attachment::Attachment( const Attachment &other )
87 : d_ptr(new AttachmentPrivate(*other.d_func()) )
88 {
89 
90 }
91 
92 Attachment::~Attachment()
93 {
94  delete d_ptr;
95 }
96 
97 
98 bool Attachment::operator==( const Attachment &a ) const
99 {
100  const Q_D( Attachment );
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;
105  }
106  return d->mData == a.d_func()->mData &&
107  d->mMimetype == a.d_func()->mMimetype &&
108  d->mLabel == a.d_func()->mLabel;
109 }
110 
111 void Attachment::operator=( const Attachment &a )
112 {
113  *d_ptr = *a.d_ptr;
114 }
115 
116 QUrl Attachment::url() const
117 {
118  const Q_D( Attachment );
119  return d->mUrl;
120 }
121 
122 QByteArray Attachment::data() const
123 {
124  const Q_D( Attachment );
125  return d->mData;
126 }
127 
128 QString Attachment::mimetype() const
129 {
130  const Q_D( Attachment );
131  return d->mMimetype;
132 }
133 
134 void Attachment::setLabel( const QString& label )
135 {
136  Q_D( Attachment );
137  d->mLabel = label;
138 }
139 
140 QString Attachment::label() const
141 {
142  const Q_D( Attachment );
143  return d->mLabel;
144 }
145 
146 
147 
148 class NoteMessageWrapper::NoteMessageWrapperPrivate
149 {
150  public:
151  NoteMessageWrapperPrivate()
152  : classification( Public )
153  {
154  }
155 
156  NoteMessageWrapperPrivate( const KMime::Message::Ptr &msg )
157  : textFormat( Qt::PlainText ),
158  classification( Public )
159  {
160  readMimeMessage(msg);
161  }
162 
163  void readMimeMessage(const KMime::Message::Ptr &msg );
164 
165  KMime::Content* createCustomPart() const;
166  void parseCustomPart( KMime::Content * );
167 
168  KMime::Content* createAttachmentPart( const Attachment & ) const;
169  void parseAttachmentPart( KMime::Content * );
170 
171  QString uid;
172  QString title;
173  QString text;
174  Qt::TextFormat textFormat;
175  QString from;
176  KDateTime creationDate;
177  KDateTime lastModifiedDate;
178  QMap< QString, QString > custom;
179  QList<Attachment> attachments;
180  Classification classification;
181 };
182 
183 void NoteMessageWrapper::NoteMessageWrapperPrivate::readMimeMessage(const KMime::Message::Ptr& msg)
184 {
185  if (!msg.get()) {
186  kWarning() << "Empty message";
187  return;
188  }
189  title = msg->subject( true )->asUnicodeString();
190  text = msg->mainBodyPart()->decodedText( true ); //remove trailing whitespace, so we get rid of " " in empty notes
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;
196  }
197 
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";
203  }
204  }
205 
206  if (KMime::Headers::Base *uidHeader = msg->headerByType(X_NOTES_UID_HEADER)) {
207  uid = uidHeader->asUnicodeString();
208  }
209 
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;
216  }
217  }
218 
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 ) {
224  parseCustomPart(c);
225  } else if ( type == CONTENT_TYPE_ATTACHMENT ) {
226  parseAttachmentPart(c);
227  } else {
228  qWarning() << "unknown type " << type;
229  }
230  }
231  }
232 }
233 
234 QDomDocument createXMLDocument()
235 {
236  QDomDocument document;
237  QString p = "version=\"1.0\" encoding=\"UTF-8\"";
238  document.appendChild(document.createProcessingInstruction( "xml", p ) );
239  return document;
240 }
241 
242 QDomDocument loadDocument(KMime::Content *part)
243 {
244  QString errorMsg;
245  int errorLine, errorColumn;
246  QDomDocument document;
247  bool ok = document.setContent( part->body(), &errorMsg, &errorLine, &errorColumn );
248  if ( !ok ) {
249  kWarning() << part->body();
250  qWarning( "Error loading document: %s, line %d, column %d", qPrintable( errorMsg ), errorLine, errorColumn );
251  return QDomDocument();
252  }
253  return document;
254 }
255 
256 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createCustomPart() const
257 {
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() );
266  e.appendChild( t );
267  element.appendChild( e );
268  document.appendChild( element );
269  }
270  content->setBody( document.toString().toLatin1() );
271  return content;
272 }
273 
274 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseCustomPart( KMime::Content* part )
275 {
276  QDomDocument document = loadDocument( part );
277  if (document.isNull()) {
278  return;
279  }
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() );
284  return;
285  }
286 
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());
291  } else {
292  kDebug() <<"Node is not an element";
293  Q_ASSERT(false);
294  }
295  }
296 }
297 
298 KMime::Content* NoteMessageWrapper::NoteMessageWrapperPrivate::createAttachmentPart( const Attachment &a ) const
299 {
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 ) );
304  } else {
305  content->setBody( a.data() );
306  }
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 ) );
310  }
311  content->contentTransferEncoding()->setEncoding( KMime::Headers::CEbase64 );
312  content->contentDisposition()->setDisposition( KMime::Headers::CDattachment );
313  content->contentDisposition()->setFilename( "attachment" );
314  return content;
315 }
316 
317 void NoteMessageWrapper::NoteMessageWrapperPrivate::parseAttachmentPart( KMime::Content *part )
318 {
319  QString label;
320  if ( KMime::Headers::Base *labelHeader = part->headerByType( X_NOTES_LABEL_HEADER ) ) {
321  label = labelHeader->asUnicodeString();
322  }
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);
327  } else {
328  Attachment attachment( part->decodedContent(), part->contentType()->mimeType() );
329  attachment.setLabel( label );
330  attachments.append(attachment);
331  }
332 }
333 
334 NoteMessageWrapper::NoteMessageWrapper()
335 : d_ptr( new NoteMessageWrapperPrivate() )
336 {
337 }
338 
339 NoteMessageWrapper::NoteMessageWrapper( const KMime::Message::Ptr &msg )
340 : d_ptr( new NoteMessageWrapperPrivate(msg) )
341 {
342 }
343 
344 NoteMessageWrapper::~NoteMessageWrapper()
345 {
346  delete d_ptr;
347 }
348 
349 KMime::Message::Ptr NoteMessageWrapper::message() const
350 {
351  const Q_D( NoteMessageWrapper );
352  KMime::Message::Ptr msg = KMime::Message::Ptr( new KMime::Message() );
353 
354  QString title = i18nc( "The default name for new notes.", "New Note" );
355  if ( !d->title.isEmpty() ) {
356  title = d->title;
357  }
358  // Need a non-empty body part so that the serializer regards this as a valid message.
359  QString text = QLatin1String(" ");
360  if ( !d->text.isEmpty() ) {
361  text = d->text;
362  }
363 
364  KDateTime creationDate = KDateTime::currentLocalDateTime();
365  if ( d->creationDate.isValid() ) {
366  creationDate = d->creationDate;
367  }
368 
369  KDateTime lastModifiedDate = KDateTime::currentLocalDateTime();
370  if ( d->lastModifiedDate.isValid() ) {
371  lastModifiedDate = d->lastModifiedDate;
372  }
373 
374  QString uid;
375  if ( !d->uid.isEmpty() ) {
376  uid = d->uid;
377  } else {
378  uid = QUuid::createUuid();
379  }
380 
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 ) );
388 
389  QString classification = QString::fromLatin1(CLASSIFICATION_PUBLIC);
390  switch ( d->classification ) {
391  case Private:
392  classification = QString::fromLatin1(CLASSIFICATION_PRIVATE);
393  break;
394  case Confidential:
395  classification = QString::fromLatin1(CLASSIFICATION_CONFIDENTIAL);
396  break;
397  default:
398  //do nothing
399  break;
400  }
401  msg->appendHeader( new KMime::Headers::Generic( X_NOTES_CLASSIFICATION_HEADER, msg.get(), classification, ENCODING ) );
402 
403  foreach (const Attachment &a, d->attachments) {
404  msg->addContent( d->createAttachmentPart(a) );
405  }
406 
407  if ( !d->custom.isEmpty() ) {
408  msg->addContent( d->createCustomPart() );
409  }
410 
411  msg->assemble();
412  return msg;
413 }
414 
415 void NoteMessageWrapper::setUid( const QString &uid )
416 {
417  Q_D( NoteMessageWrapper );
418  d->uid = uid;
419 }
420 
421 QString NoteMessageWrapper::uid() const
422 {
423  const Q_D( NoteMessageWrapper );
424  return d->uid;
425 }
426 
427 void NoteMessageWrapper::setClassification( NoteMessageWrapper::Classification classification )
428 {
429  Q_D( NoteMessageWrapper );
430  d->classification = classification;
431 }
432 
433 NoteMessageWrapper::Classification NoteMessageWrapper::classification() const
434 {
435  const Q_D( NoteMessageWrapper );
436  return d->classification;
437 }
438 
439 void NoteMessageWrapper::setLastModifiedDate( const KDateTime& lastModifiedDate )
440 {
441  Q_D( NoteMessageWrapper );
442  d->lastModifiedDate = lastModifiedDate;
443 }
444 
445 KDateTime NoteMessageWrapper::lastModifiedDate() const
446 {
447  const Q_D( NoteMessageWrapper );
448  return d->lastModifiedDate;
449 }
450 
451 void NoteMessageWrapper::setCreationDate( const KDateTime &creationDate )
452 {
453  Q_D( NoteMessageWrapper );
454  d->creationDate = creationDate;
455 }
456 
457 KDateTime NoteMessageWrapper::creationDate() const
458 {
459  const Q_D( NoteMessageWrapper );
460  return d->creationDate;
461 }
462 
463 void NoteMessageWrapper::setFrom( const QString &from )
464 {
465  Q_D( NoteMessageWrapper );
466  d->from = from;
467 }
468 
469 QString NoteMessageWrapper::from() const
470 {
471  const Q_D( NoteMessageWrapper );
472  return d->from;
473 }
474 
475 void NoteMessageWrapper::setTitle( const QString &title )
476 {
477  Q_D( NoteMessageWrapper );
478  d->title = title;
479 }
480 
481 QString NoteMessageWrapper::title() const
482 {
483  const Q_D( NoteMessageWrapper );
484  return d->title;
485 }
486 
487 void NoteMessageWrapper::setText( const QString &text, Qt::TextFormat format )
488 {
489  Q_D( NoteMessageWrapper );
490  d->text = text;
491  d->textFormat = format;
492 }
493 
494 QString NoteMessageWrapper::text() const
495 {
496  const Q_D( NoteMessageWrapper );
497  return d->text;
498 }
499 
500 Qt::TextFormat NoteMessageWrapper::textFormat() const
501 {
502  const Q_D( NoteMessageWrapper );
503  return d->textFormat;
504 }
505 
506 QString NoteMessageWrapper::toPlainText() const
507 {
508  const Q_D( NoteMessageWrapper );
509  if ( d->textFormat == Qt::PlainText ) {
510  return d->text;
511  }
512 
513  //From cleanHtml in kdepimlibs/kcalutils/incidenceformatter.cpp
514  QRegExp rx( QLatin1String("<body[^>]*>(.*)</body>"), Qt::CaseInsensitive );
515  rx.indexIn( d->text );
516  QString body = rx.cap( 1 );
517 
518  return Qt::escape( body.remove( QRegExp( QLatin1String("<[^>]*>") ) ).trimmed() );
519 }
520 
521 QList<Attachment> &NoteMessageWrapper::attachments()
522 {
523  Q_D( NoteMessageWrapper );
524  return d->attachments;
525 }
526 
527 QMap< QString, QString > &NoteMessageWrapper::custom()
528 {
529  Q_D( NoteMessageWrapper );
530  return d->custom;
531 }
532 
533 
534 
535 QString noteIconName()
536 {
537  return QString::fromLatin1( "text-plain" );
538 }
539 
540 QString noteMimeType()
541 {
542  return QString::fromLatin1( "text/x-vnd.akonadi.note" );
543 }
544 
545 } //End Namepsace
546 } //End Namepsace
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:39 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal