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;
54 :
QObject( parent ), s_endErrDlg(0)
77 art->setServerId(a->id());
79 art->setDoMail(
false);
93 QByteArray chset = Locale::defaultCharset( g );
99 art->setServerId(g->account()->id());
100 art->setDoPost(
true);
101 art->setDoMail(
false);
102 art->newsgroups()->fromUnicodeString(g->groupname(), art->defaultCharset());
118 if (
knGlobals.settings()->useOwnCharset() ) {
119 chset = Locale::defaultCharset( g );
121 chset = a->contentType()->charset();
130 art->setServerId(g->account()->id());
131 art->setDoPost(post);
132 art->setDoMail(mail);
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" ) ) {
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)
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 );
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';
248 quoted +=
"> " +(*line) +
'\n';
261 if ( art->doMail() &&
knGlobals.settings()->useExternalMailer() ) {
263 art->setDoMail(
false);
264 if (!art->doPost()) {
270 KNComposer *c=
new KNComposer(art, quoted, notRewraped,
true, authorDislikesMailCopies, authorWantsMailCopies);
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();
300 art->setDoPost(
false);
301 art->setDoMail(
true);
306 QString
subject=(
"Fwd: "+a->subject()->asUnicodeString());
307 art->subject()->fromUnicodeString(subject, a->subject()->rfc2047Charset());
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)"));
332 KMime::Content::List al = a->attachments(
false );
333 foreach ( KMime::Content *c, al )
334 art->addContent(
new KMime::Content(c->head(), c->body()) );
340 if (
knGlobals.settings()->useExternalMailer() ) {
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;
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."));
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);
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"));
439 if ( KMessageBox::No==KMessageBox::questionYesNo(
knGlobals.topWidget,
440 i18n(
"Do you really want to supersede this article?"), QString(), KGuiItem(i18n(
"Supersede")), KStandardGuiItem::cancel() ) )
447 nntp = boost::static_pointer_cast<KNGroup>( a->collection() )->account();
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);
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();
508 if (
knGlobals.settings()->useExternalMailer() ) {
518 art->setDoMail(
true);
519 art->setDoPost(
false);
520 art->to()->addAddress((*address));
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);
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);
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()) {
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) ) ) {
623 s_endErrDlg->
append( (*it)->subject()->asUnicodeString(), i18n(
"Unable to load article.") );
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() );
644 if ( (*it)->doPost() && !(*it)->posted() ) {
645 ser =
knGlobals.accountManager()->account( (*it)->serverId() );
649 if ( (*it)->doMail() && !(*it)->mailed() ) {
650 int transportId = TransportManager::self()->defaultTransportId();
663 if(!
knGlobals.folderManager()->loadOutbox()) {
664 KMessageBox::error(
knGlobals.topWidget, i18n(
"Unable to load the outbox-folder."));
669 for(
int i=0; i< ob->length(); ++i)
670 lst.append(ob->at(i));
680 if ( !(*it)->close() )
701 if ( (*it)->article() == a )
710 (*it)->setConfig(
false );
724 if(art->collection()!=
knGlobals.folderManager()->outbox())
727 KMessageBox::information(
knGlobals.topWidget, i18n(
"You canceled the article posting. The unsent articles are stored in the \"Outbox\" folder."));
738 if(art->collection()!=
knGlobals.folderManager()->outbox())
744 art->setEditDisabled(
true);
750 art->setPosted(
true);
751 if(art->doMail() && !art->mailed()) {
759 art->setMailed(
true);
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."));
779 KPIMIdentities::Identity id;
783 id = boost::static_pointer_cast<
KNGroup>( col )->identity();
785 id = boost::static_pointer_cast<KNGroup>( col )->account()->identity();
788 id = boost::static_pointer_cast<
KNNntpAccount>( col )->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() );
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() ) );
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() ) {
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 );
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() ) );
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."));
927 bool ownArticle =
false;
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."));
996 delCom=
knGlobals.articleManager()->deleteArticles(lst,
true);
1000 delCom=
knGlobals.articleManager()->deleteArticles(lst,
false);
1017 KWindowSystem::activateWindow(com->winId());
1035 setCaption( i18n(
"Errors While Sending") );
1036 setButtons( Close );
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);
1045 mError->setWordWrap(
true );
1062 item->setIcon( UserIcon(
"snderr") );
1072 QString tmp = i18n(
"<b>Error message:</b><br />") + item->
error();
1078 #include "knarticlefactory.moc"
composerResult result() const
Represents an account on a news server.
void setCanceled(bool b=true)
void sendMailExternal(const QString &address=QString(), const QString &subject=QString(), const QString &body=QString())
Send a mail via an external program.
KNComposer * findComposer(KNLocalArticle::Ptr a)
boost::shared_ptr< KNLocalArticle > Ptr
Shared pointer to a KNLocalArticle. To be used instead of raw KNLocalArticle*.
void append(const QString &subject, const QString &error)
static void saveWindowSize(const QString &name, const QSize &s)
bool cancelAllowed(KNArticle::Ptr a)
KNLocalArticle::Ptr newArticle(KNCollection::Ptr col, const QByteArray &defChset, bool withXHeaders=true, KNArticle::Ptr origPost=KNArticle::Ptr())
Generate a new article to edit before posting.
void emitJob(KNJobData *j)
Send the job to the scheduler and append it to the job queue.
void createReply(KNRemoteArticle::Ptr a, const QString &selectedText=QString(), bool post=true, bool mail=false)
virtual QByteArray text(quint32 serialNumber) const =0
QList< KNComposer * > mCompList
Abstract base class for all KNode internal jobs.
bool closeComposeWindows()
static void restoreWindowSize(const QString &name, QWidget *d, const QSize &defaultSize)
static KNGlobals * self()
Return the KNGlobals instance.
void createPosting(KNNntpAccount::Ptr a)
Representation of a news group.
boost::shared_ptr< KNFolder > Ptr
Shared pointer to a KNFolder.
void slotComposerDone(KNComposer *com)
Message send error dialog.
boost::shared_ptr< KNNntpAccount > Ptr
Shared pointer to a KNNntpAccount.
void createForward(KNArticle::Ptr a)
QLabel * mError
Error message label.
Post a article to the given news server.
This class encapsulates an article, that is stored locally in an MBOX-file.
KPIMIdentities::IdentityManager * identityManager()
Returns the identity manager.
QListWidget * mErrorList
Error list widget.
KNSendErrorDialog * s_endErrDlg
void edit(KNLocalArticle::Ptr a)
KNJobItem::Ptr data() const
QString error() const
Returns the error message of this item.
virtual const KPIMIdentities::Identity & identity() const
Returns the global identity (or the default one when none is set yet).
KNode::Settings * settings()
Returns the KConfigXT generated settings object.
bool canceled() const
Returns true if the job has been canceled by the user.
void deleteComposerForArticle(KNLocalArticle::Ptr a)
void createMail(KMime::Types::Mailbox *address)
void slotSendErrorDialogDone()
void sendArticles(KNLocalArticle::List &l, bool now=true)
KNLocalArticle::Ptr article() const
void createSupersede(KNArticle::Ptr a)
static QString rewrapStringList(const QStringList &text, int wrapAt, QChar quoteChar, bool stopAtSig, bool alwaysSpace)
used for rewarping a text when replying to a message or inserting a file into a box ...
QString errorString() const
Returns the error message.
boost::shared_ptr< KNRemoteArticle > Ptr
Shared pointer to a KNRemoteArticle. To be used instead of raw KNRemoteArticle*.
boost::shared_ptr< KNCollection > Ptr
Shared pointer to a KNCollection.
void showSendErrorDialog()
void createCancel(KNArticle::Ptr a)
boost::shared_ptr< KNArticle > Ptr
Shared pointer to a KNArticle. To be used instead of raw KNArticle*.
bool success() const
Returns true if the job finished successfully.
bool applyChanges()
Applies changes from the editor into the article being edited.
KNArticleFactory(QObject *parent=0)
boost::shared_ptr< KNArticleCollection > Ptr
Shared pointer to a KNArticle.
KNRemoteArticle represents an article, whos body has to be retrieved from a remote host or from the l...
boost::shared_ptr< KNServerInfo > Ptr
Shared pointer to a KNServerInfo.
void processJob(KNJobData *j)
The actual work is done here.
#define knGlobals
Keep compatibility with the old way.
Sends a mail to a SMTP server.
boost::shared_ptr< KNGroup > Ptr
Shared pointer to a KNGroup.
void slotHighlighted(int idx)