Factor out the shared parts of the agent action manager setup.
[kdepim.git] / knode / knarticlefactory.cpp
blob216735979469440e575ceb6e0b13cb73a59c3bc6
1 /*
2 KNode, the KDE newsreader
3 Copyright (c) 1999-2006 the KNode authors.
4 See file AUTHORS for details
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
16 #include "knarticlefactory.h"
18 #include "knglobals.h"
19 #include "kngroupmanager.h"
20 #include "knaccountmanager.h"
21 #include "knfoldermanager.h"
22 #include "knarticlemanager.h"
23 #include "knfolder.h"
24 #include "kncomposer.h"
25 #include "knnntpaccount.h"
26 #include "mailsendjob.h"
27 #include "nntpjobs.h"
28 #include "utilities.h"
29 #include "resource.h"
30 #include "settings.h"
31 #include "utils/locale.h"
33 #include <QByteArray>
34 #include <QList>
35 #include <QListWidget>
36 #include <KPIMIdentities/Identity>
37 #include <KPIMIdentities/IdentityManager>
38 #include <KPIMUtils/Email>
39 #include <QLabel>
40 #include <kiconloader.h>
41 #include <klocale.h>
42 #include <kmessagebox.h>
43 #include <kwindowsystem.h>
44 #include <ktoolinvocation.h>
45 #include <kvbox.h>
46 #include <mailtransport/transportmanager.h>
49 using namespace KNode;
50 using namespace KNode::Utilities;
51 using namespace MailTransport;
53 KNArticleFactory::KNArticleFactory( QObject *parent )
54 : QObject( parent ), s_endErrDlg(0)
59 KNArticleFactory::~KNArticleFactory()
61 for ( QList<KNComposer*>::Iterator it = mCompList.begin(); it != mCompList.end(); ++it )
62 delete (*it);
63 delete s_endErrDlg;
67 void KNArticleFactory::createPosting( KNNntpAccount::Ptr a )
69 if(!a)
70 return;
72 KNLocalArticle::Ptr art = newArticle( a, Locale::defaultCharset() );
74 if(!art)
75 return;
77 art->setServerId(a->id());
78 art->setDoPost(true);
79 art->setDoMail(false);
81 KNComposer *c = new KNComposer( art, QString(), QString(), true, false, false, false );
82 mCompList.append( c );
83 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
84 c->show();
88 void KNArticleFactory::createPosting( KNGroup::Ptr g )
90 if(!g)
91 return;
93 QByteArray chset = Locale::defaultCharset( g );
94 KNLocalArticle::Ptr art = newArticle( g, chset );
96 if(!art)
97 return;
99 art->setServerId(g->account()->id());
100 art->setDoPost(true);
101 art->setDoMail(false);
102 art->newsgroups()->fromUnicodeString(g->groupname(), art->defaultCharset());
103 KNComposer *c = new KNComposer( art, QString(), QString(), true, false, false, false );
104 mCompList.append( c );
105 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
106 c->show();
110 void KNArticleFactory::createReply( KNRemoteArticle::Ptr a, const QString &selectedText, bool post, bool mail )
112 if(!a)
113 return;
115 KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( a->collection() );
117 QByteArray chset;
118 if ( knGlobals.settings()->useOwnCharset() ) {
119 chset = Locale::defaultCharset( g );
120 } else {
121 chset = a->contentType()->charset();
124 //create new article
125 KNLocalArticle::Ptr art = newArticle( g, chset, true, a );
127 if(!art)
128 return;
130 art->setServerId(g->account()->id());
131 art->setDoPost(post);
132 art->setDoMail(mail);
134 //------------------------- <Headers> ----------------------------
136 //subject
137 QString subject=a->subject()->asUnicodeString();
138 if ( subject.left(3).toUpper() != "RE:" )
139 subject.prepend("Re: ");
140 art->subject()->fromUnicodeString(subject, a->subject()->rfc2047Charset());
142 //newsgroups
143 KMime::Headers::FollowUpTo *fup2=a->followUpTo(false);
144 if(fup2 && !fup2->isEmpty()) {
145 if( ( fup2->as7BitString(false).toUpper()=="POSTER" ) ) { //Followup-To: poster
146 if( post && // user wanted to reply by public posting?
147 // ask the user if she wants to ignore this F'up-To: poster
148 ( KMessageBox::Yes != KMessageBox::questionYesNo(knGlobals.topWidget,
149 i18n("The author has requested a reply by email instead\nof a followup to the newsgroup. (Followup-To: poster)\nDo you want to reply in public anyway?"), QString(), KGuiItem(i18n("Reply Public")), KGuiItem(i18n("Reply by Email"))) ))
151 art->setDoPost(false);
152 art->setDoMail(true);
154 art->newsgroups()->from7BitString(a->newsgroups()->as7BitString(false));
156 else
157 art->newsgroups()->from7BitString(fup2->as7BitString(false));
159 else
160 art->newsgroups()->from7BitString(a->newsgroups()->as7BitString(false));
162 //To
163 KMime::Headers::ReplyTo *replyTo=a->replyTo(false);
164 KMime::Types::Mailbox address;
165 if(replyTo && !replyTo->isEmpty()) {
166 foreach( const KMime::Types::Mailbox &mbox, replyTo->mailboxes() ) {
167 art->to()->addAddress( mbox );
170 else {
171 KMime::Headers::From *from=a->from();
172 foreach( const KMime::Types::Mailbox &mbox, from->mailboxes() ) {
173 art->to()->addAddress( mbox );
177 //References
178 KMime::Headers::References *references=a->references(false);
179 QByteArray refs;
180 if (references)
181 refs=references->as7BitString(false);
182 else
183 refs = "";
185 art->references()->from7BitString(refs);
186 art->references()->appendIdentifier(a->messageID()->as7BitString(false));
188 //Mail-Copies-To
189 bool authorDislikesMailCopies=false;
190 bool authorWantsMailCopies=false;
191 KMime::Headers::MailCopiesTo *mailCopiesTo=a->mailCopiesTo(false);
193 if( mailCopiesTo && !mailCopiesTo->isEmpty() ) {
194 authorDislikesMailCopies = mailCopiesTo->neverCopy();
195 authorWantsMailCopies = mailCopiesTo->alwaysCopy();
196 if (authorWantsMailCopies) // warn the user
197 KMessageBox::information( knGlobals.topWidget, i18n("The author requested a mail copy of your reply. (Mail-Copies-To header)"),
198 QString(), "mailCopiesToWarning" );
199 if ( authorWantsMailCopies && !mailCopiesTo->mailboxes().isEmpty() ) {
200 art->to()->clear();
201 foreach ( const KMime::Types::Mailbox &mbox, mailCopiesTo->mailboxes() ) {
202 art->to()->addAddress( mbox );
207 //------------------------- </Headers> ---------------------------
209 //--------------------------- <Body> -----------------------------
211 // attribution line
212 QString attribution = knGlobals.settings()->intro();
213 QString name( a->from()->displayNames().join( ", ") );
214 if ( name.isEmpty() && !a->from()->isEmpty() )
215 name = QString::fromLatin1( a->from()->addresses().first() );
216 attribution.replace(QRegExp("%NAME"),name);
217 if ( !a->from()->isEmpty() )
218 attribution.replace(QRegExp("%EMAIL"), QString::fromLatin1(a->from()->addresses().first()));
219 attribution.replace( QRegExp("%DATE"), KGlobal::locale()->formatDateTime(a->date()->dateTime().toLocalZone().dateTime(), KLocale::LongDate) );
220 QString msid = a->messageID()->identifier();
221 attribution.replace( QRegExp("%MSIDX"), msid );
222 attribution.replace( QRegExp("%MSID"), QLatin1Char('<') + msid + QLatin1Char('>') );
223 attribution.replace(QRegExp("%GROUP"),g->groupname());
224 attribution.replace(QRegExp("%L"),"\n");
225 attribution+="\n\n";
227 QString quoted=attribution;
228 QString notRewraped;
229 QStringList text;
230 QStringList::Iterator line;
231 bool incSig = knGlobals.settings()->includeSignature();
233 if (selectedText.isEmpty()) {
234 KMime::Content *tc = a->textContent();
235 if(tc)
236 text = tc->decodedText( true, knGlobals.settings()->removeTrailingNewlines() ).split( '\n' );
238 else
239 text = selectedText.split('\n');
241 for(line=text.begin(); line!=text.end(); ++line) {
242 if(!incSig && (*line)=="-- ")
243 break;
245 if ((*line)[0]=='>')
246 quoted += '>' + (*line) + '\n'; // second quote level without space
247 else
248 quoted += "> " +(*line) + '\n';
251 if ( knGlobals.settings()->rewrap() ) { //rewrap original article
253 notRewraped=quoted; // store the original text in here, the user can request it in the composer
254 quoted=attribution;
256 quoted += KNHelper::rewrapStringList( text, knGlobals.settings()->maxLineLength(), '>', !incSig, false );
259 //-------------------------- </Body> -----------------------------
261 if ( art->doMail() && knGlobals.settings()->useExternalMailer() ) {
262 sendMailExternal(address.prettyAddress(), subject, quoted);
263 art->setDoMail(false);
264 if (!art->doPost()) {
265 return;
269 //open composer
270 KNComposer *c=new KNComposer(art, quoted, notRewraped, true, authorDislikesMailCopies, authorWantsMailCopies);
271 mCompList.append( c );
272 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
273 c->show();
277 void KNArticleFactory::createForward( KNArticle::Ptr a )
279 if(!a)
280 return;
282 KMime::Headers::ContentType *ct=a->contentType();
283 QByteArray chset;
284 bool incAtt = ( !knGlobals.settings()->useExternalMailer() &&
285 ct->isMultipart() && ct->isSubtype("mixed") &&
286 KMessageBox::Yes == KMessageBox::questionYesNo(knGlobals.topWidget,
287 i18n("This article contains attachments. Do you want them to be forwarded as well?"), QString(), KGuiItem(i18n("Forward")), KGuiItem(i18n("Do Not Forward")))
290 if ( knGlobals.settings()->useOwnCharset() )
291 chset = Locale::defaultCharset();
292 else
293 chset = a->contentType()->charset();
295 //create new article
296 KNLocalArticle::Ptr art = newArticle( knGlobals.groupManager()->currentGroup(), chset );
297 if(!art)
298 return;
300 art->setDoPost(false);
301 art->setDoMail(true);
303 //------------------------- <Headers> ----------------------------
305 //subject
306 QString subject=("Fwd: "+a->subject()->asUnicodeString());
307 art->subject()->fromUnicodeString(subject, a->subject()->rfc2047Charset());
309 //------------------------- </Headers> ---------------------------
311 //--------------------------- <Body> -----------------------------
313 QString fwd = QString("\n--------------- %1\n\n").arg(i18n("Forwarded message (begin)"));
315 fwd+=( i18n("Subject") + ": " + a->subject()->asUnicodeString() + '\n' );
316 fwd+=( i18n("From") + ": " + a->from()->asUnicodeString() + '\n' );
317 fwd+=( i18n("Date") + ": " + a->date()->asUnicodeString() + '\n' );
318 fwd+=( i18n("Newsgroup") + ": " + a->newsgroups()->asUnicodeString() + "\n\n" );
320 KMime::Content *text=a->textContent();
321 if(text)
322 fwd += text->decodedText( false, false );
324 fwd += QString("\n--------------- %1\n").arg(i18n("Forwarded message (end)"));
326 //--------------------------- </Body> ----------------------------
329 //------------------------ <Attachments> -------------------------
331 if(incAtt) {
332 KMime::Content::List al = a->attachments( false );
333 foreach ( KMime::Content *c, al )
334 art->addContent( new KMime::Content(c->head(), c->body()) );
337 //------------------------ </Attachments> ------------------------
340 if ( knGlobals.settings()->useExternalMailer() ) {
341 sendMailExternal( QString(), subject, fwd );
342 return;
345 //open composer
346 KNComposer *c = new KNComposer( art, fwd, QString(), true );
347 mCompList.append( c );
348 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
349 c->show();
353 void KNArticleFactory::createCancel( KNArticle::Ptr a )
355 if(!cancelAllowed(a))
356 return;
358 if( KMessageBox::No == KMessageBox::questionYesNo( knGlobals.topWidget,
359 i18n("Do you really want to cancel this article?"), QString(), KGuiItem(i18n("Cancel Article")), KStandardGuiItem::cancel() ) )
360 return;
362 bool sendNow;
363 switch (KMessageBox::warningYesNoCancel(knGlobals.topWidget, i18n("Do you want to send the cancel\nmessage now or later?"), i18n("Question"),KGuiItem(i18n("&Now")),KGuiItem(i18n("&Later")))) {
364 case KMessageBox::Yes : sendNow = true; break;
365 case KMessageBox::No : sendNow = false; break;
366 default : return;
369 KNGroup::Ptr grp;
370 KNNntpAccount::Ptr nntp;
372 if ( a->type() == KNArticle::ATremote )
373 nntp = boost::static_pointer_cast<KNGroup>( a->collection() )->account();
374 else {
375 if(!nntp)
376 nntp=knGlobals.accountManager()->first();
377 if(!nntp) {
378 KMessageBox::error(knGlobals.topWidget, i18n("You have no valid news accounts configured."));
379 return;
381 KNLocalArticle::Ptr la = boost::static_pointer_cast<KNLocalArticle>( a );
382 la->setCanceled(true);
383 la->updateListItem();
384 nntp=knGlobals.accountManager()->account(la->serverId());
387 if ( !a->newsgroups()->isEmpty() )
388 grp = knGlobals.groupManager()->group(a->newsgroups()->groups().first(), nntp);
390 KNLocalArticle::Ptr art = newArticle( grp, "us-ascii", false );
392 if(!art)
393 return;
395 //init
396 art->setDoPost(true);
397 art->setDoMail(false);
399 //server
400 art->setServerId(nntp->id());
402 //subject
403 KMime::Headers::MessageID *msgId=a->messageID();
404 QByteArray tmp;
405 tmp="cancel of "+msgId->as7BitString(false);
406 art->subject()->from7BitString(tmp);
408 //newsgroups
409 art->newsgroups()->from7BitString(a->newsgroups()->as7BitString(false));
411 //control
412 tmp="cancel "+msgId->as7BitString(false);
413 art->control()->from7BitString(tmp);
415 //Lines
416 art->lines()->setNumberOfLines(1);
418 //body
419 art->fromUnicodeString(QString::fromLatin1("cancel by original author\n"));
421 //assemble
422 art->assemble();
424 //send
425 KNLocalArticle::List lst;
426 lst.append(art);
427 sendArticles( lst, sendNow );
431 void KNArticleFactory::createSupersede( KNArticle::Ptr a )
433 if (!a)
434 return;
436 if(!cancelAllowed(a))
437 return;
439 if ( KMessageBox::No==KMessageBox::questionYesNo( knGlobals.topWidget,
440 i18n("Do you really want to supersede this article?"), QString(), KGuiItem(i18n("Supersede")), KStandardGuiItem::cancel() ) )
441 return;
443 KNGroup::Ptr grp;
444 KNNntpAccount::Ptr nntp;
446 if ( a->type() == KNArticle::ATremote )
447 nntp = boost::static_pointer_cast<KNGroup>( a->collection() )->account();
448 else {
449 KNLocalArticle::Ptr la = boost::static_pointer_cast<KNLocalArticle>( a );
450 la->setCanceled(true);
451 la->updateListItem();
452 nntp=knGlobals.accountManager()->account(la->serverId());
453 if(!nntp)
454 nntp=knGlobals.accountManager()->first();
455 if(!nntp) {
456 KMessageBox::error(knGlobals.topWidget, i18n("You have no valid news accounts configured."));
457 return;
461 if ( !a->newsgroups()->isEmpty() )
462 grp = knGlobals.groupManager()->group(a->newsgroups()->groups().first(), nntp);
464 //new article
465 KNLocalArticle::Ptr art = newArticle( grp, a->contentType()->charset() );
467 if(!art)
468 return;
470 art->setDoPost(true);
471 art->setDoMail(false);
473 //server
474 art->setServerId(nntp->id());
476 //subject
477 art->subject()->fromUnicodeString(a->subject()->asUnicodeString(), a->subject()->rfc2047Charset());
479 //newsgroups
480 art->newsgroups()->from7BitString(a->newsgroups()->as7BitString(false));
482 //followup-to
483 art->followUpTo()->from7BitString(a->followUpTo()->as7BitString(false));
485 //References
486 if ( !a->references()->isEmpty() )
487 art->references()->from7BitString( a->references()->as7BitString(false) );
489 //Supersedes
490 art->supersedes()->from7BitString(a->messageID()->as7BitString(false));
492 //Body
493 QString text;
494 KMime::Content *textContent=a->textContent();
495 if(textContent)
496 text = textContent->decodedText();
498 //open composer
499 KNComposer *c=new KNComposer(art, text);
500 mCompList.append( c );
501 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
502 c->show();
506 void KNArticleFactory::createMail(KMime::Types::Mailbox *address)
508 if ( knGlobals.settings()->useExternalMailer() ) {
509 sendMailExternal(address->prettyAddress());
510 return;
513 //create new article
514 KNLocalArticle::Ptr art = newArticle( knGlobals.groupManager()->currentGroup(), Locale::defaultCharset() );
515 if(!art)
516 return;
518 art->setDoMail(true);
519 art->setDoPost(false);
520 art->to()->addAddress((*address));
522 //open composer
523 KNComposer *c = new KNComposer( art, QString(), QString(), true );
524 mCompList.append( c );
525 connect(c, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
526 c->show();
530 void KNArticleFactory::sendMailExternal(const QString &address, const QString &subject, const QString &body)
532 KUrl mailtoURL;
533 QStringList queries;
534 QString query;
535 mailtoURL.setProtocol("mailto");
537 if (!address.isEmpty())
538 mailtoURL.setPath(address);
539 if (!subject.isEmpty())
540 queries.append("subject="+KUrl::toPercentEncoding(subject));
541 if (!body.isEmpty())
542 queries.append("body="+KUrl::toPercentEncoding(body));
544 if (queries.count() > 0) {
545 query = '?';
546 for ( QStringList::Iterator it = queries.begin(); it != queries.end(); ++it ) {
547 if (it != queries.begin())
548 query.append( '&' );
549 query.append((*it));
553 if (!query.isEmpty())
554 mailtoURL.setQuery(query);
556 KToolInvocation::invokeMailer(mailtoURL);
560 void KNArticleFactory::edit( KNLocalArticle::Ptr a )
562 if(!a)
563 return;
565 KNComposer *com=findComposer(a);
566 if(com) {
567 #ifdef Q_OS_UNIX
568 KWindowSystem::activateWindow(com->winId());
569 #endif
570 return;
573 if(a->editDisabled()) {
574 KMessageBox::sorry(knGlobals.topWidget, i18n("This article cannot be edited."));
575 return;
578 //load article body
579 if(!a->hasContent())
580 knGlobals.articleManager()->loadArticle(a);
582 //open composer
583 com = new KNComposer( a, QString() );
584 mCompList.append( com );
585 connect(com, SIGNAL(composerDone(KNComposer*)), this, SLOT(slotComposerDone(KNComposer*)));
586 com->show();
590 void KNArticleFactory::sendArticles( KNLocalArticle::List &l, bool now )
592 KNJobData *job=0;
593 KNServerInfo::Ptr ser;
595 KNLocalArticle::List unsent, sent;
596 for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
597 if ( (*it)->pending() )
598 unsent.append( (*it) );
599 else
600 sent.append( (*it) );
603 if(!sent.isEmpty()) {
604 showSendErrorDialog();
605 for ( KNLocalArticle::List::Iterator it = sent.begin(); it != sent.end(); ++it )
606 s_endErrDlg->append( (*it)->subject()->asUnicodeString(), i18n("Article has already been sent.") );
609 if(!now) {
610 knGlobals.articleManager()->moveIntoFolder(unsent, knGlobals.folderManager()->outbox());
611 return;
615 for ( KNLocalArticle::List::Iterator it = unsent.begin(); it != unsent.end(); ++it ) {
617 if ( (*it)->isLocked() )
618 continue;
620 if ( !(*it)->hasContent() ) {
621 if ( !knGlobals.articleManager()->loadArticle( (*it) ) ) {
622 showSendErrorDialog();
623 s_endErrDlg->append( (*it)->subject()->asUnicodeString(), i18n("Unable to load article.") );
624 continue;
629 // filter out internal headers
630 QByteArray head = (*it)->head();
631 KMime::Headers::Base *header = 0;
632 while ( true ) {
633 header = KMime::HeaderParsing::extractFirstHeader( head );
634 if ( !header ) {
635 break;
637 if ( qstrncmp( header->type(), "X-KNode", 7 ) == 0 ) {
638 (*it)->removeHeader( header->type() );
641 (*it)->assemble(); // Validate change made above
644 if ( (*it)->doPost() && !(*it)->posted() ) {
645 ser = knGlobals.accountManager()->account( (*it)->serverId() );
646 job = new ArticlePostJob( this, ser, (*it) );
647 emitJob(job);
649 if ( (*it)->doMail() && !(*it)->mailed() ) {
650 int transportId = TransportManager::self()->defaultTransportId();
651 job = new MailSendJob( this, transportId, (*it) );
652 emitJob(job);
658 void KNArticleFactory::sendOutbox()
660 KNLocalArticle::List lst;
661 KNFolder::Ptr ob;
663 if(!knGlobals.folderManager()->loadOutbox()) {
664 KMessageBox::error(knGlobals.topWidget, i18n("Unable to load the outbox-folder."));
665 return;
668 ob=knGlobals.folderManager()->outbox();
669 for(int i=0; i< ob->length(); i++)
670 lst.append(ob->at(i));
672 sendArticles( lst, true );
676 bool KNArticleFactory::closeComposeWindows()
678 while ( !mCompList.isEmpty() ) {
679 QList<KNComposer*>::Iterator it = mCompList.begin();
680 if ( !(*it)->close() )
681 return false;
684 return true;
688 void KNArticleFactory::deleteComposerForArticle( KNLocalArticle::Ptr a )
690 KNComposer *com = findComposer( a );
691 if ( com ) {
692 mCompList.removeAll( com );
693 com->deleteLater();
698 KNComposer* KNArticleFactory::findComposer( KNLocalArticle::Ptr a )
700 for ( QList<KNComposer*>::Iterator it = mCompList.begin(); it != mCompList.end(); ++it )
701 if ( (*it)->article() == a )
702 return (*it);
703 return 0;
707 void KNArticleFactory::configChanged()
709 for ( QList<KNComposer*>::Iterator it = mCompList.begin(); it != mCompList.end(); ++it )
710 (*it)->setConfig( false );
714 void KNArticleFactory::processJob(KNJobData *j)
716 KNLocalArticle::Ptr art = boost::static_pointer_cast<KNLocalArticle>( j->data() );
717 KNLocalArticle::List lst;
718 lst.append(art);
720 if(j->canceled()) {
721 delete j;
723 //sending of this article was canceled => move it to the "Outbox-Folder"
724 if(art->collection()!=knGlobals.folderManager()->outbox())
725 knGlobals.articleManager()->moveIntoFolder(lst, knGlobals.folderManager()->outbox());
727 KMessageBox::information(knGlobals.topWidget, i18n("You canceled the article posting. The unsent articles are stored in the \"Outbox\" folder."));
729 return;
732 if(!j->success()) {
733 showSendErrorDialog();
734 s_endErrDlg->append(art->subject()->asUnicodeString(), j->errorString());
735 delete j; //unlock article
737 //sending of this article failed => move it to the "Outbox-Folder"
738 if(art->collection()!=knGlobals.folderManager()->outbox())
739 knGlobals.articleManager()->moveIntoFolder(lst, knGlobals.folderManager()->outbox());
741 else {
743 //disable edit
744 art->setEditDisabled(true);
746 switch(j->type()) {
748 case KNJobData::JTpostArticle:
749 delete j; //unlock article
750 art->setPosted(true);
751 if(art->doMail() && !art->mailed()) { //article has been posted, now mail it
752 sendArticles( lst, true );
753 return;
755 break;
757 case KNJobData::JTmail:
758 delete j; //unlock article
759 art->setMailed(true);
760 break;
762 default: break;
765 //article has been sent successfully => move it to the "Sent-folder"
766 knGlobals.articleManager()->moveIntoFolder(lst, knGlobals.folderManager()->sent());
771 KNLocalArticle::Ptr KNArticleFactory::newArticle( KNCollection::Ptr col, const QByteArray &defChset, bool withXHeaders, KNArticle::Ptr origPost )
773 if ( knGlobals.settings()->generateMessageID() && knGlobals.settings()->hostname().isEmpty() ) {
774 KMessageBox::sorry(knGlobals.topWidget, i18n("Please set a hostname for the generation\nof the message-id or disable it."));
775 return KNLocalArticle::Ptr();
778 KNLocalArticle::Ptr art( new KNLocalArticle( KNArticleCollection::Ptr() ) );
779 KPIMIdentities::Identity id;
781 if (col) {
782 if (col->type() == KNCollection::CTgroup) {
783 id = boost::static_pointer_cast<KNGroup>( col )->identity();
784 if ( id.isNull() ) {
785 id = boost::static_pointer_cast<KNGroup>( col )->account()->identity();
787 } else if (col->type() == KNCollection::CTnntpAccount) {
788 id = boost::static_pointer_cast<KNNntpAccount>( col )->identity();
791 if ( id.isNull() ) {
792 id = KNGlobals::self()->settings()->identity();
794 // Identity UOID
795 KMime::Headers::Generic *xKnodeIdentity = new KMime::Headers::Generic( "X-KNode-Identity",
796 art.get(),
797 QByteArray::number( id.uoid() ) );
798 art->setHeader( xKnodeIdentity );
800 //Message-id
801 if ( knGlobals.settings()->generateMessageID() )
802 art->messageID()->generate( knGlobals.settings()->hostname().toLatin1() );
804 //From
805 KMime::Headers::From *from=art->from();
806 if ( KPIMUtils::isValidSimpleAddress( id.primaryEmailAddress() ) ) {
807 from->fromUnicodeString( id.fullEmailAddr(), Locale::defaultCharset() );
808 } else {
809 KMessageBox::sorry( knGlobals.topWidget,
810 i18n( "<qt>Please enter a valid email address for the "
811 "identity named <emphasis>%1</emphasis> "
812 "at the identity section of the configuration dialog.</qt>",
813 id.identityName() ) );
814 return KNLocalArticle::Ptr();
817 //Reply-To
818 if ( KPIMUtils::isValidAddress( id.replyToAddr() ) == KPIMUtils::AddressOk ) {
819 art->replyTo()->fromUnicodeString( id.replyToAddr(), Locale::defaultCharset() );
820 } else {
821 art->removeHeader( "Reply-To" );
824 //Mail-Copies-To
825 if ( KPIMUtils::isValidAddress( id.property( "Mail-Copies-To" ).toString() ) == KPIMUtils::AddressOk ) {
826 art->mailCopiesTo()->fromUnicodeString( id.property( "Mail-Copies-To" ).toString(), Locale::defaultCharset() );
827 } else {
828 art->removeHeader( "Mail-Copies-To" );
831 //Organization
832 if ( !id.organization().trimmed().isEmpty() ) {
833 art->organization()->fromUnicodeString( id.organization(), Locale::defaultCharset() );
834 } else {
835 art->removeHeader( "Organization" );
838 //Date
839 art->date()->setDateTime( KDateTime::currentLocalDateTime() );
841 //User-Agent
842 if( !knGlobals.settings()->noUserAgent() ) {
843 art->userAgent()->from7BitString("KNode/" KNODE_VERSION);
846 //Mime
847 KMime::Headers::ContentType *type=art->contentType();
848 type->setMimeType("text/plain");
850 type->setCharset(defChset);
852 if ( defChset.toLower() == "us-ascii" )
853 art->contentTransferEncoding()->setEncoding(KMime::Headers::CE7Bit);
854 else
855 art->contentTransferEncoding()->setEncoding( knGlobals.settings()->allow8BitBody() ? KMime::Headers::CE8Bit : KMime::Headers::CEquPr );
857 //X-Headers
858 if(withXHeaders) {
859 XHeader::List xhdr = knGlobals.settings()->xHeaders();
860 for ( XHeader::List::Iterator it = xhdr.begin(); it != xhdr.end(); ++it ) {
861 QString value = (*it).value();
862 if(origPost) {
863 QString name( origPost->from()->displayNames().join(", ") );
864 if ( name.isEmpty() && !origPost->from()->isEmpty() )
865 name = QString::fromLatin1( origPost->from()->addresses().first() );
866 value.replace(QRegExp("%NAME"), name);
867 if ( !origPost->from()->isEmpty() )
868 value.replace( QRegExp("%EMAIL"), QString::fromLatin1(origPost->from()->addresses().first() ) );
870 else
871 if ( value.indexOf( "%NAME" ) != -1 || value.indexOf( "%EMAIL" ) != -1 )
872 continue;
874 art->setHeader( new KMime::Headers::Generic( (*it).name().toLatin1(), art.get(), value,
875 Locale::defaultCharset() ) );
879 return art;
883 bool KNArticleFactory::cancelAllowed( KNArticle::Ptr a )
885 if(!a)
886 return false;
888 if(a->type()==KNArticle::ATlocal) {
889 KNLocalArticle::Ptr localArt = boost::static_pointer_cast<KNLocalArticle>( a );
891 if(localArt->doMail() && !localArt->doPost()) {
892 KMessageBox::sorry(knGlobals.topWidget, i18n("Emails cannot be canceled or superseded."));
893 return false;
896 KMime::Headers::Control *ctrl=localArt->control(false);
897 if(ctrl && ctrl->isCancel()) {
898 KMessageBox::sorry(knGlobals.topWidget, i18n("Cancel messages cannot be canceled or superseded."));
899 return false;
902 if(!localArt->posted()) {
903 KMessageBox::sorry(knGlobals.topWidget, i18n("Only sent articles can be canceled or superseded."));
904 return false;
907 if(localArt->canceled()) {
908 KMessageBox::sorry(knGlobals.topWidget, i18n("This article has already been canceled or superseded."));
909 return false;
912 KMime::Headers::MessageID *mid=localArt->messageID(false);
913 if(!mid || mid->isEmpty()) {
914 KMessageBox::sorry(knGlobals.topWidget, i18n(
915 "This article cannot be canceled or superseded,\n\
916 because its message-id has not been created by KNode.\n\
917 But you can look for your article in the newsgroup\n\
918 and cancel (or supersede) it there."));
919 return false;
922 return true;
924 else if ( a->type() == KNArticle::ATremote ) {
925 KNRemoteArticle::Ptr remArt = boost::static_pointer_cast<KNRemoteArticle>( a );
926 KPIMIdentities::IdentityManager *im = KNGlobals::self()->identityManager();
927 bool ownArticle = false;
928 const QList<QByteArray> fromAddr = remArt->from()->addresses();
929 foreach ( const QByteArray &addr, fromAddr ) {
930 if ( im->thatIsMe( QString::fromLatin1( addr ) ) ) {
931 ownArticle = true;
932 break;
935 if(!ownArticle) {
936 KMessageBox::sorry(knGlobals.topWidget, i18n("This article does not appear to be from you.\nYou can only cancel or supersede your own articles."));
937 return false;
940 if(!remArt->hasContent()) {
941 KMessageBox::sorry(knGlobals.topWidget, i18n("You have to download the article body\nbefore you can cancel or supersede the article."));
942 return false;
945 return true;
948 return false;
952 void KNArticleFactory::showSendErrorDialog()
954 if(!s_endErrDlg) {
955 s_endErrDlg=new KNSendErrorDialog();
956 connect(s_endErrDlg, SIGNAL(closeClicked()), this, SLOT(slotSendErrorDialogDone()));
958 s_endErrDlg->show();
962 void KNArticleFactory::slotComposerDone(KNComposer *com)
964 bool delCom=true;
965 KNLocalArticle::List lst;
966 lst.append(com->article());
968 switch(com->result()) {
970 case KNComposer::CRsendNow:
971 delCom=com->hasValidData();
972 if(delCom) {
973 if ( com->applyChanges() )
974 sendArticles( lst, true );
975 else
976 delCom = false;
978 break;
980 case KNComposer::CRsendLater:
981 delCom=com->hasValidData();
982 if(delCom) {
983 if ( com->applyChanges() )
984 sendArticles( lst, false );
985 else
986 delCom = false;
988 break;
990 case KNComposer::CRsave :
991 com->applyChanges();
992 knGlobals.articleManager()->moveIntoFolder(lst, knGlobals.folderManager()->drafts());
993 break;
995 case KNComposer::CRdelAsk:
996 delCom=knGlobals.articleManager()->deleteArticles(lst, true);
997 break;
999 case KNComposer::CRdel:
1000 delCom=knGlobals.articleManager()->deleteArticles(lst, false);
1001 break;
1003 case KNComposer::CRcancel:
1004 // just close...
1005 break;
1007 default: break;
1011 if ( delCom ) {
1012 mCompList.removeAll( com );
1013 com->deleteLater();
1015 #ifdef Q_OS_UNIX
1016 else
1017 KWindowSystem::activateWindow(com->winId());
1018 #endif
1022 void KNArticleFactory::slotSendErrorDialogDone()
1024 s_endErrDlg->deleteLater();
1025 s_endErrDlg=0;
1029 //======================================================================================================
1032 KNSendErrorDialog::KNSendErrorDialog()
1033 : KDialog( knGlobals.topWidget )
1035 setCaption( i18n("Errors While Sending") );
1036 setButtons( Close );
1037 KVBox *page = new KVBox( this );
1038 setMainWidget( page );
1039 setDefaultButton( Close );
1041 new QLabel(QString("<b>%1</b><br>%2").arg(i18n("Errors occurred while sending these articles:"))
1042 .arg(i18n("The unsent articles are stored in the \"Outbox\" folder.")), page);
1043 mErrorList = new QListWidget( page );
1044 mError = new QLabel( QString(), page );
1045 mError->setWordWrap( true );
1047 connect( mErrorList, SIGNAL(currentRowChanged(int)), SLOT(slotHighlighted(int)) );
1049 KNHelper::restoreWindowSize("sendDlg", this, QSize(320,250));
1053 KNSendErrorDialog::~KNSendErrorDialog()
1055 KNHelper::saveWindowSize("sendDlg", size());
1059 void KNSendErrorDialog::append(const QString &subject, const QString &error)
1061 ErrorListItem *item = new ErrorListItem( subject, error );
1062 item->setIcon( UserIcon("snderr") );
1063 mErrorList->addItem( item );
1064 mErrorList->setCurrentItem( item );
1068 void KNSendErrorDialog::slotHighlighted(int idx)
1070 ErrorListItem *item = static_cast<ErrorListItem*>( mErrorList->item( idx ) );
1071 if ( item ) {
1072 QString tmp = i18n("<b>Error message:</b><br />") + item->error();
1073 mError->setText( tmp );
1077 //-------------------------------
1078 #include "knarticlefactory.moc"