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"
24 #include "kncomposer.h"
25 #include "knnntpaccount.h"
26 #include "mailsendjob.h"
28 #include "utilities.h"
31 #include "utils/locale.h"
35 #include <QListWidget>
36 #include <KPIMIdentities/Identity>
37 #include <KPIMIdentities/IdentityManager>
38 #include <KPIMUtils/Email>
40 #include <kiconloader.h>
42 #include <kmessagebox.h>
43 #include <kwindowsystem.h>
44 #include <ktoolinvocation.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
)
67 void KNArticleFactory::createPosting( KNNntpAccount::Ptr a
)
72 KNLocalArticle::Ptr art
= newArticle( a
, Locale::defaultCharset() );
77 art
->setServerId(a
->id());
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
*)));
88 void KNArticleFactory::createPosting( KNGroup::Ptr g
)
93 QByteArray chset
= Locale::defaultCharset( g
);
94 KNLocalArticle::Ptr art
= newArticle( g
, chset
);
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
*)));
110 void KNArticleFactory::createReply( KNRemoteArticle::Ptr a
, const QString
&selectedText
, bool post
, bool mail
)
115 KNGroup::Ptr g
= boost::static_pointer_cast
<KNGroup
>( a
->collection() );
118 if ( knGlobals
.settings()->useOwnCharset() ) {
119 chset
= Locale::defaultCharset( g
);
121 chset
= a
->contentType()->charset();
125 KNLocalArticle::Ptr art
= newArticle( g
, chset
, true, a
);
130 art
->setServerId(g
->account()->id());
131 art
->setDoPost(post
);
132 art
->setDoMail(mail
);
134 //------------------------- <Headers> ----------------------------
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());
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));
157 art
->newsgroups()->from7BitString(fup2
->as7BitString(false));
160 art
->newsgroups()->from7BitString(a
->newsgroups()->as7BitString(false));
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
);
171 KMime::Headers::From
*from
=a
->from();
172 foreach( const KMime::Types::Mailbox
&mbox
, from
->mailboxes() ) {
173 art
->to()->addAddress( mbox
);
178 KMime::Headers::References
*references
=a
->references(false);
181 refs
=references
->as7BitString(false);
185 art
->references()->from7BitString(refs
);
186 art
->references()->appendIdentifier(a
->messageID()->as7BitString(false));
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() ) {
201 foreach ( const KMime::Types::Mailbox
&mbox
, mailCopiesTo
->mailboxes() ) {
202 art
->to()->addAddress( mbox
);
207 //------------------------- </Headers> ---------------------------
209 //--------------------------- <Body> -----------------------------
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");
227 QString quoted
=attribution
;
230 QStringList::Iterator line
;
231 bool incSig
= knGlobals
.settings()->includeSignature();
233 if (selectedText
.isEmpty()) {
234 KMime::Content
*tc
= a
->textContent();
236 text
= tc
->decodedText( true, knGlobals
.settings()->removeTrailingNewlines() ).split( '\n' );
239 text
= selectedText
.split('\n');
241 for(line
=text
.begin(); line
!=text
.end(); ++line
) {
242 if(!incSig
&& (*line
)=="-- ")
246 quoted
+= '>' + (*line
) + '\n'; // second quote level without space
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
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()) {
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
*)));
277 void KNArticleFactory::createForward( KNArticle::Ptr a
)
282 KMime::Headers::ContentType
*ct
=a
->contentType();
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();
293 chset
= a
->contentType()->charset();
296 KNLocalArticle::Ptr art
= newArticle( knGlobals
.groupManager()->currentGroup(), chset
);
300 art
->setDoPost(false);
301 art
->setDoMail(true);
303 //------------------------- <Headers> ----------------------------
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();
322 fwd
+= text
->decodedText( false, false );
324 fwd
+= QString("\n--------------- %1\n").arg(i18n("Forwarded message (end)"));
326 //--------------------------- </Body> ----------------------------
329 //------------------------ <Attachments> -------------------------
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
);
346 KNComposer
*c
= new KNComposer( art
, fwd
, QString(), true );
347 mCompList
.append( c
);
348 connect(c
, SIGNAL(composerDone(KNComposer
*)), this, SLOT(slotComposerDone(KNComposer
*)));
353 void KNArticleFactory::createCancel( KNArticle::Ptr a
)
355 if(!cancelAllowed(a
))
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() ) )
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;
370 KNNntpAccount::Ptr nntp
;
372 if ( a
->type() == KNArticle::ATremote
)
373 nntp
= boost::static_pointer_cast
<KNGroup
>( a
->collection() )->account();
376 nntp
=knGlobals
.accountManager()->first();
378 KMessageBox::error(knGlobals
.topWidget
, i18n("You have no valid news accounts configured."));
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 );
396 art
->setDoPost(true);
397 art
->setDoMail(false);
400 art
->setServerId(nntp
->id());
403 KMime::Headers::MessageID
*msgId
=a
->messageID();
405 tmp
="cancel of "+msgId
->as7BitString(false);
406 art
->subject()->from7BitString(tmp
);
409 art
->newsgroups()->from7BitString(a
->newsgroups()->as7BitString(false));
412 tmp
="cancel "+msgId
->as7BitString(false);
413 art
->control()->from7BitString(tmp
);
416 art
->lines()->setNumberOfLines(1);
419 art
->fromUnicodeString(QString::fromLatin1("cancel by original author\n"));
425 KNLocalArticle::List lst
;
427 sendArticles( lst
, sendNow
);
431 void KNArticleFactory::createSupersede( KNArticle::Ptr a
)
436 if(!cancelAllowed(a
))
439 if ( KMessageBox::No
==KMessageBox::questionYesNo( knGlobals
.topWidget
,
440 i18n("Do you really want to supersede this article?"), QString(), KGuiItem(i18n("Supersede")), KStandardGuiItem::cancel() ) )
444 KNNntpAccount::Ptr nntp
;
446 if ( a
->type() == KNArticle::ATremote
)
447 nntp
= boost::static_pointer_cast
<KNGroup
>( a
->collection() )->account();
449 KNLocalArticle::Ptr la
= boost::static_pointer_cast
<KNLocalArticle
>( a
);
450 la
->setCanceled(true);
451 la
->updateListItem();
452 nntp
=knGlobals
.accountManager()->account(la
->serverId());
454 nntp
=knGlobals
.accountManager()->first();
456 KMessageBox::error(knGlobals
.topWidget
, i18n("You have no valid news accounts configured."));
461 if ( !a
->newsgroups()->isEmpty() )
462 grp
= knGlobals
.groupManager()->group(a
->newsgroups()->groups().first(), nntp
);
465 KNLocalArticle::Ptr art
= newArticle( grp
, a
->contentType()->charset() );
470 art
->setDoPost(true);
471 art
->setDoMail(false);
474 art
->setServerId(nntp
->id());
477 art
->subject()->fromUnicodeString(a
->subject()->asUnicodeString(), a
->subject()->rfc2047Charset());
480 art
->newsgroups()->from7BitString(a
->newsgroups()->as7BitString(false));
483 art
->followUpTo()->from7BitString(a
->followUpTo()->as7BitString(false));
486 if ( !a
->references()->isEmpty() )
487 art
->references()->from7BitString( a
->references()->as7BitString(false) );
490 art
->supersedes()->from7BitString(a
->messageID()->as7BitString(false));
494 KMime::Content
*textContent
=a
->textContent();
496 text
= textContent
->decodedText();
499 KNComposer
*c
=new KNComposer(art
, text
);
500 mCompList
.append( c
);
501 connect(c
, SIGNAL(composerDone(KNComposer
*)), this, SLOT(slotComposerDone(KNComposer
*)));
506 void KNArticleFactory::createMail(KMime::Types::Mailbox
*address
)
508 if ( knGlobals
.settings()->useExternalMailer() ) {
509 sendMailExternal(address
->prettyAddress());
514 KNLocalArticle::Ptr art
= newArticle( knGlobals
.groupManager()->currentGroup(), Locale::defaultCharset() );
518 art
->setDoMail(true);
519 art
->setDoPost(false);
520 art
->to()->addAddress((*address
));
523 KNComposer
*c
= new KNComposer( art
, QString(), QString(), true );
524 mCompList
.append( c
);
525 connect(c
, SIGNAL(composerDone(KNComposer
*)), this, SLOT(slotComposerDone(KNComposer
*)));
530 void KNArticleFactory::sendMailExternal(const QString
&address
, const QString
&subject
, const QString
&body
)
535 mailtoURL
.setProtocol("mailto");
537 if (!address
.isEmpty())
538 mailtoURL
.setPath(address
);
539 if (!subject
.isEmpty())
540 queries
.append("subject="+KUrl::toPercentEncoding(subject
));
542 queries
.append("body="+KUrl::toPercentEncoding(body
));
544 if (queries
.count() > 0) {
546 for ( QStringList::Iterator it
= queries
.begin(); it
!= queries
.end(); ++it
) {
547 if (it
!= queries
.begin())
553 if (!query
.isEmpty())
554 mailtoURL
.setQuery(query
);
556 KToolInvocation::invokeMailer(mailtoURL
);
560 void KNArticleFactory::edit( KNLocalArticle::Ptr a
)
565 KNComposer
*com
=findComposer(a
);
568 KWindowSystem::activateWindow(com
->winId());
573 if(a
->editDisabled()) {
574 KMessageBox::sorry(knGlobals
.topWidget
, i18n("This article cannot be edited."));
580 knGlobals
.articleManager()->loadArticle(a
);
583 com
= new KNComposer( a
, QString() );
584 mCompList
.append( com
);
585 connect(com
, SIGNAL(composerDone(KNComposer
*)), this, SLOT(slotComposerDone(KNComposer
*)));
590 void KNArticleFactory::sendArticles( KNLocalArticle::List
&l
, bool now
)
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
) );
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.") );
610 knGlobals
.articleManager()->moveIntoFolder(unsent
, knGlobals
.folderManager()->outbox());
615 for ( KNLocalArticle::List::Iterator it
= unsent
.begin(); it
!= unsent
.end(); ++it
) {
617 if ( (*it
)->isLocked() )
620 if ( !(*it
)->hasContent() ) {
621 if ( !knGlobals
.articleManager()->loadArticle( (*it
) ) ) {
622 showSendErrorDialog();
623 s_endErrDlg
->append( (*it
)->subject()->asUnicodeString(), i18n("Unable to load article.") );
629 // filter out internal headers
630 QByteArray head
= (*it
)->head();
631 KMime::Headers::Base
*header
= 0;
633 header
= KMime::HeaderParsing::extractFirstHeader( head
);
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
) );
649 if ( (*it
)->doMail() && !(*it
)->mailed() ) {
650 int transportId
= TransportManager::self()->defaultTransportId();
651 job
= new MailSendJob( this, transportId
, (*it
) );
658 void KNArticleFactory::sendOutbox()
660 KNLocalArticle::List lst
;
663 if(!knGlobals
.folderManager()->loadOutbox()) {
664 KMessageBox::error(knGlobals
.topWidget
, i18n("Unable to load the outbox-folder."));
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() )
688 void KNArticleFactory::deleteComposerForArticle( KNLocalArticle::Ptr a
)
690 KNComposer
*com
= findComposer( a
);
692 mCompList
.removeAll( com
);
698 KNComposer
* KNArticleFactory::findComposer( KNLocalArticle::Ptr a
)
700 for ( QList
<KNComposer
*>::Iterator it
= mCompList
.begin(); it
!= mCompList
.end(); ++it
)
701 if ( (*it
)->article() == a
)
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
;
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."));
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());
744 art
->setEditDisabled(true);
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 );
757 case KNJobData::JTmail
:
758 delete j
; //unlock article
759 art
->setMailed(true);
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
;
782 if (col
->type() == KNCollection::CTgroup
) {
783 id
= boost::static_pointer_cast
<KNGroup
>( col
)->identity();
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();
792 id
= KNGlobals::self()->settings()->identity();
795 KMime::Headers::Generic
*xKnodeIdentity
= new KMime::Headers::Generic( "X-KNode-Identity",
797 QByteArray::number( id
.uoid() ) );
798 art
->setHeader( xKnodeIdentity
);
801 if ( knGlobals
.settings()->generateMessageID() )
802 art
->messageID()->generate( knGlobals
.settings()->hostname().toLatin1() );
805 KMime::Headers::From
*from
=art
->from();
806 if ( KPIMUtils::isValidSimpleAddress( id
.primaryEmailAddress() ) ) {
807 from
->fromUnicodeString( id
.fullEmailAddr(), Locale::defaultCharset() );
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();
818 if ( KPIMUtils::isValidAddress( id
.replyToAddr() ) == KPIMUtils::AddressOk
) {
819 art
->replyTo()->fromUnicodeString( id
.replyToAddr(), Locale::defaultCharset() );
821 art
->removeHeader( "Reply-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() );
828 art
->removeHeader( "Mail-Copies-To" );
832 if ( !id
.organization().trimmed().isEmpty() ) {
833 art
->organization()->fromUnicodeString( id
.organization(), Locale::defaultCharset() );
835 art
->removeHeader( "Organization" );
839 art
->date()->setDateTime( KDateTime::currentLocalDateTime() );
842 if( !knGlobals
.settings()->noUserAgent() ) {
843 art
->userAgent()->from7BitString("KNode/" KNODE_VERSION
);
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
);
855 art
->contentTransferEncoding()->setEncoding( knGlobals
.settings()->allow8BitBody() ? KMime::Headers::CE8Bit
: KMime::Headers::CEquPr
);
859 XHeader::List xhdr
= knGlobals
.settings()->xHeaders();
860 for ( XHeader::List::Iterator it
= xhdr
.begin(); it
!= xhdr
.end(); ++it
) {
861 QString value
= (*it
).value();
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() ) );
871 if ( value
.indexOf( "%NAME" ) != -1 || value
.indexOf( "%EMAIL" ) != -1 )
874 art
->setHeader( new KMime::Headers::Generic( (*it
).name().toLatin1(), art
.get(), value
,
875 Locale::defaultCharset() ) );
883 bool KNArticleFactory::cancelAllowed( KNArticle::Ptr a
)
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."));
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."));
902 if(!localArt
->posted()) {
903 KMessageBox::sorry(knGlobals
.topWidget
, i18n("Only sent articles can be canceled or superseded."));
907 if(localArt
->canceled()) {
908 KMessageBox::sorry(knGlobals
.topWidget
, i18n("This article has already been canceled or superseded."));
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."));
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
) ) ) {
936 KMessageBox::sorry(knGlobals
.topWidget
, i18n("This article does not appear to be from you.\nYou can only cancel or supersede your own articles."));
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."));
952 void KNArticleFactory::showSendErrorDialog()
955 s_endErrDlg
=new KNSendErrorDialog();
956 connect(s_endErrDlg
, SIGNAL(closeClicked()), this, SLOT(slotSendErrorDialogDone()));
962 void KNArticleFactory::slotComposerDone(KNComposer
*com
)
965 KNLocalArticle::List lst
;
966 lst
.append(com
->article());
968 switch(com
->result()) {
970 case KNComposer::CRsendNow
:
971 delCom
=com
->hasValidData();
973 if ( com
->applyChanges() )
974 sendArticles( lst
, true );
980 case KNComposer::CRsendLater
:
981 delCom
=com
->hasValidData();
983 if ( com
->applyChanges() )
984 sendArticles( lst
, false );
990 case KNComposer::CRsave
:
992 knGlobals
.articleManager()->moveIntoFolder(lst
, knGlobals
.folderManager()->drafts());
995 case KNComposer::CRdelAsk
:
996 delCom
=knGlobals
.articleManager()->deleteArticles(lst
, true);
999 case KNComposer::CRdel
:
1000 delCom
=knGlobals
.articleManager()->deleteArticles(lst
, false);
1003 case KNComposer::CRcancel
:
1012 mCompList
.removeAll( com
);
1017 KWindowSystem::activateWindow(com
->winId());
1022 void KNArticleFactory::slotSendErrorDialogDone()
1024 s_endErrDlg
->deleteLater();
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
) );
1072 QString tmp
= i18n("<b>Error message:</b><br />") + item
->error();
1073 mError
->setText( tmp
);
1077 //-------------------------------
1078 #include "knarticlefactory.moc"