Exemple #1
0
void MailClient::send( const KPIMIdentities::Identity &identity,
                       const QString &from, const QString &_to,
                       const QString &cc, const QString &subject,
                       const QString &body, bool hidden, bool bccMe,
                       const QString &attachment, const QString &mailTransport )
{
  Q_UNUSED( identity );
  Q_UNUSED( hidden );

#ifdef MAILCLIENTTEST_UNITTEST
  mUnitTestResult.message = KMime::Message::Ptr();
  mUnitTestResult.from.clear();
  mUnitTestResult.to.clear();
  mUnitTestResult.cc.clear();
  mUnitTestResult.bcc.clear();
  mUnitTestResult.transportId = -1;
#endif

  if ( !MailTransport::TransportManager::self()->showTransportCreationDialog(
        0, MailTransport::TransportManager::IfNoTransportExists ) ) {
    kError() << "Error while creating transport";
    emit finished( ResultErrorCreatingTransport, i18n( "Error while creating transport" ) );
    return;
  }

  // We must have a recipients list for most MUAs. Thus, if the 'to' list
  // is empty simply use the 'from' address as the recipient.
  QString to = _to;
  if ( to.isEmpty() ) {
    to = from;
  }
  kDebug() << "\nFrom:" << from
           << "\nTo:" << to
           << "\nCC:" << cc
           << "\nSubject:" << subject << "\nBody: \n" << body
           << "\nAttachment:\n" << attachment
           << "\nmailTransport: " << mailTransport;

  QTime timer;
  timer.start();

  MailTransport::Transport *transport =
    MailTransport::TransportManager::self()->transportByName( mailTransport );

  if ( !transport ) {
    transport =
      MailTransport::TransportManager::self()->transportByName(
        MailTransport::TransportManager::self()->defaultTransportName() );
  }

  if ( !transport ) {
    kError() << "Error fetching transport; mailTransport"
             << mailTransport << MailTransport::TransportManager::self()->defaultTransportName();
    emit finished( ResultErrorFetchingTransport,
                   i18n( "Error fetching transport. Unable to send invitations" ) );
    return;
  }

  const int transportId = transport->id();

  // gather config values
  KConfig config( QLatin1String( "mailviewerrc" ) );

  KConfigGroup configGroup( &config, QLatin1String( "Invitations" ) );
  const bool outlookConformInvitation = configGroup.readEntry( "LegacyBodyInvites",
#ifdef KDEPIM_ENTERPRISE_BUILD
                                                               true
#else
                                                               false
#endif
                                                             );

  // Now build the message we like to send. The message KMime::Message::Ptr instance
  // will be the root message that has 2 additional message. The body itself and
  // the attached cal.ics calendar file.
  KMime::Message::Ptr message = KMime::Message::Ptr( new KMime::Message );
  message->contentTransferEncoding()->clear();  // 7Bit, decoded.

  // Set the headers

  message->userAgent()->fromUnicodeString(
    KProtocolManager::userAgentForApplication(
      QLatin1String( "KOrganizer" ), QLatin1String( KDEPIMLIBS_VERSION ) ), "utf-8" );

  message->from()->fromUnicodeString( from, "utf-8" );
  message->to()->fromUnicodeString( to, "utf-8" );
  message->cc()->fromUnicodeString( cc, "utf-8" );
  if( bccMe ) {
    message->bcc()->fromUnicodeString( from, "utf-8" ); //from==me, right?
  }
  message->date()->setDateTime( KDateTime::currentLocalDateTime() );
  message->subject()->fromUnicodeString( subject, "utf-8" );

  if ( outlookConformInvitation ) {
    message->contentType()->setMimeType( "text/calendar" );
    message->contentType()->setCharset( "utf-8" );
    message->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" );
    message->contentType()->setParameter( QLatin1String( "method" ), QLatin1String( "request" ) );

    if ( !attachment.isEmpty() ) {
      KMime::Headers::ContentDisposition *disposition =
        new KMime::Headers::ContentDisposition( message.get() );
      disposition->setDisposition( KMime::Headers::CDinline );
      message->setHeader( disposition );
      message->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
      message->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) );
    }
  } else {
    // We need to set following 4 lines by hand else KMime::Content::addContent
    // will create a new Content instance for us to attach the main message
    // what we don't need cause we already have the main message instance where
    // 2 additional messages are attached.
    KMime::Headers::ContentType *ct = message->contentType();
    ct->setMimeType( "multipart/mixed" );
    ct->setBoundary( KMime::multiPartBoundary() );
    ct->setCategory( KMime::Headers::CCcontainer );

    // Set the first multipart, the body message.
    KMime::Content *bodyMessage = new KMime::Content;
    KMime::Headers::ContentDisposition *bodyDisposition =
      new KMime::Headers::ContentDisposition( bodyMessage );
    bodyDisposition->setDisposition( KMime::Headers::CDinline );
    bodyMessage->contentType()->setMimeType( "text/plain" );
    bodyMessage->contentType()->setCharset( "utf-8" );
    bodyMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
    bodyMessage->setBody( KMime::CRLFtoLF( body.toUtf8() ) );
    message->addContent( bodyMessage );

    // Set the sedcond multipart, the attachment.
    if ( !attachment.isEmpty() ) {
      KMime::Content *attachMessage = new KMime::Content;
      KMime::Headers::ContentDisposition *attachDisposition =
        new KMime::Headers::ContentDisposition( attachMessage );
      attachDisposition->setDisposition( KMime::Headers::CDattachment );
      attachMessage->contentType()->setMimeType( "text/calendar" );
      attachMessage->contentType()->setCharset( "utf-8" );
      attachMessage->contentType()->setName( QLatin1String( "cal.ics" ), "utf-8" );
      attachMessage->contentType()->setParameter( QLatin1String( "method" ),
                                                  QLatin1String( "request" ) );
      attachMessage->setHeader( attachDisposition );
      attachMessage->contentTransferEncoding()->setEncoding( KMime::Headers::CEquPr );
      attachMessage->setBody( KMime::CRLFtoLF( attachment.toUtf8() ) );
      message->addContent( attachMessage );
    }
  }

  // Job done, attach the both multiparts and assemble the message.
  message->assemble();

  // Put the newly created item in the MessageQueueJob.
  MailTransport::MessageQueueJob *qjob = new MailTransport::MessageQueueJob( this );
  qjob->transportAttribute().setTransportId( transportId );
  qjob->sentBehaviourAttribute().setSentBehaviour(
           MailTransport::SentBehaviourAttribute::MoveToDefaultSentCollection );

  const QString unormalizedFrom = ( transport && transport->specifySenderOverwriteAddress() ) ?
                                                         transport->senderOverwriteAddress() : from;


  const QString normalizedFrom = KPIMUtils::extractEmailAddress(
                                     KPIMUtils::normalizeAddressesAndEncodeIdn( unormalizedFrom ) );

  const QString finalFrom = KPIMUtils::extractEmailAddress( normalizedFrom );
  qjob->addressAttribute().setFrom( finalFrom );

  QStringList toStringList;
  if( !to.isEmpty() ) {
    toStringList = extractEmailAndNormalize( to );
    qjob->addressAttribute().setTo( toStringList );
  }

  QStringList ccStringList;
  if( !cc.isEmpty() ) {
    ccStringList = extractEmailAndNormalize( cc );
    qjob->addressAttribute().setCc( ccStringList );
  }

  QStringList bccStringList;
  if ( bccMe ) {
    bccStringList = extractEmailAndNormalize( from );
    qjob->addressAttribute().setBcc( bccStringList );
  }
  qjob->setMessage( message );
  connect( qjob, SIGNAL(finished(KJob*)), SLOT(handleQueueJobFinished(KJob*)) );
  qjob->start();

#ifdef MAILCLIENTTEST_UNITTEST
  mUnitTestResult.message            = message;
  mUnitTestResult.from               = finalFrom;
  mUnitTestResult.to                 = toStringList;
  mUnitTestResult.cc                 = ccStringList;
  mUnitTestResult.bcc                = bccStringList;
  mUnitTestResult.transportId        = transportId;
#endif
}
/******************************************************************************
* Send the email message specified in an event.
* Reply = 1 if the message was sent - 'errmsgs' may contain copy error messages.
*       = 0 if the message is queued for sending.
*       = -1 if the message was not sent - 'errmsgs' contains the error messages.
*/
int KAMail::send(JobData& jobdata, QStringList& errmsgs)
{
    QString err;
    KPIMIdentities::Identity identity;
    if (!jobdata.event.emailFromId())
        jobdata.from = Preferences::emailAddress();
    else
    {
        identity = Identities::identityManager()->identityForUoid(jobdata.event.emailFromId());
        if (identity.isNull())
        {
            kError() << "Identity" << jobdata.event.emailFromId() << "not found";
            errmsgs = errors(i18nc("@info", "Invalid 'From' email address.<nl/>Email identity <resource>%1</resource> not found", jobdata.event.emailFromId()));
            return -1;
        }
        if (identity.emailAddr().isEmpty())
        {
            kError() << "Identity" << identity.identityName() << "uoid" << identity.uoid() << ": no email address";
            errmsgs = errors(i18nc("@info", "Invalid 'From' email address.<nl/>Email identity <resource>%1</resource> has no email address", identity.identityName()));
            return -1;
        }
        jobdata.from = identity.fullEmailAddr();
    }
    if (jobdata.from.isEmpty())
    {
        switch (Preferences::emailFrom())
        {
#ifdef KMAIL_SUPPORTED
        case Preferences::MAIL_FROM_KMAIL:
            errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured (no default email identity found)</para>"
                                   "<para>Please set it in <application>KMail</application> or in the <application>KAlarm</application> Configuration dialog.</para>"));
            break;
#endif
        case Preferences::MAIL_FROM_SYS_SETTINGS:
            errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured.</para>"
                                   "<para>Please set it in the KDE System Settings or in the <application>KAlarm</application> Configuration dialog.</para>"));
            break;
        case Preferences::MAIL_FROM_ADDR:
        default:
            errmsgs = errors(i18nc("@info", "<para>No 'From' email address is configured.</para>"
                                   "<para>Please set it in the <application>KAlarm</application> Configuration dialog.</para>"));
            break;
        }
        return -1;
    }
    jobdata.bcc  = (jobdata.event.emailBcc() ? Preferences::emailBccAddress() : QString());
    kDebug() << "To:" << jobdata.event.emailAddresses(",")
             << endl << "Subject:" << jobdata.event.emailSubject();

    MailTransport::TransportManager* manager = MailTransport::TransportManager::self();
    MailTransport::Transport* transport = 0;
    if (Preferences::emailClient() == Preferences::sendmail)
    {
        kDebug() << "Sending via sendmail";
        const QList<MailTransport::Transport*> transports = manager->transports();
        for (int i = 0, count = transports.count();  i < count;  ++i)
        {
            if (transports[i]->type() == MailTransport::Transport::EnumType::Sendmail)
            {
                // Use the first sendmail transport found
                transport = transports[i];
                break;
            }
        }
        if (!transport)
        {
            QString command = KStandardDirs::findExe(QLatin1String("sendmail"),
                              QLatin1String("/sbin:/usr/sbin:/usr/lib"));
            transport = manager->createTransport();
            transport->setName(QLatin1String("sendmail"));
            transport->setType(MailTransport::Transport::EnumType::Sendmail);
            transport->setHost(command);
            transport->setRequiresAuthentication(false);
            transport->setStorePassword(false);
            manager->addTransport(transport);
            transport->writeConfig();
            kDebug() << "Creating sendmail transport, id=" << transport->id();
        }
    }
    else
    {
        kDebug() << "Sending via KDE";
        transport = manager->transportByName(identity.transport(), true);
        if (!transport)
        {
            kError() << "No mail transport found for identity" << identity.identityName() << "uoid" << identity.uoid();
            errmsgs = errors(i18nc("@info", "No mail transport configured for email identity <resource>%1</resource>", identity.identityName()));
            return -1;
        }
    }
    kDebug() << "Using transport" << transport->name() << ", id=" << transport->id();
    MailTransport::TransportJob* mailjob = manager->createTransportJob(transport->id());
    if (!mailjob)
    {
        kError() << "Failed to create mail transport job for identity" << identity.identityName() << "uoid" << identity.uoid();
        errmsgs = errors(i18nc("@info", "Unable to create mail transport job"));
        return -1;
    }
    KMime::Message message;
    initHeaders(message, jobdata);
    err = appendBodyAttachments(message, jobdata);
    if (!err.isNull())
    {
        kError() << "Error compiling message:" << err;
        errmsgs = errors(err);
        return -1;
    }
    mailjob->setSender(KPIMUtils::extractEmailAddress(jobdata.from));
    mailjob->setTo(jobdata.event.emailPureAddresses());
    if (!jobdata.bcc.isEmpty())
        mailjob->setBcc(QStringList(KPIMUtils::extractEmailAddress(jobdata.bcc)));
    mailjob->setData(message.encodedContent());
    mJobs.enqueue(mailjob);
    mJobData.enqueue(jobdata);
    if (mJobs.count() == 1)
    {
        // There are no jobs already active or queued, so send now
        connect(mailjob, SIGNAL(result(KJob*)), instance(), SLOT(slotEmailSent(KJob*)));
        mailjob->start();
    }
    return 0;
}