/** @short Prepare a network request This function handles delegating access to the other body parts using various schemes (ie. the special trojita-imap:// one used by Trojita for internal purposes and the cid: one for referencing to other body parts). Policy checks for filtering access to the public Internet are also performed at this level. */ QNetworkReply *MsgPartNetAccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) { Q_UNUSED(op); Q_UNUSED(outgoingData); if (!message.isValid()) { // Our message got removed in the meanwhile // FIXME: add a better class here return new Imap::Network::ForbiddenReply(this); } Q_ASSERT(message.isValid()); const Mailbox::Model *constModel = 0; Mailbox::Model::realTreeItem(message, &constModel); Q_ASSERT(constModel); Mailbox::Model *model = const_cast<Mailbox::Model *>(constModel); Q_ASSERT(model); Imap::Mailbox::TreeItemPart *part = pathToPart(message, req.url().path()); QModelIndex partIndex = part ? part->toIndex(model) : QModelIndex(); if (req.url().scheme() == QLatin1String("trojita-imap") && req.url().host() == QLatin1String("msg")) { // Internal Trojita reference if (part) { return new Imap::Network::MsgPartNetworkReply(this, partIndex); } else { qDebug() << "No such part:" << req.url(); return new Imap::Network::ForbiddenReply(this); } } else if (req.url().scheme() == QLatin1String("cid")) { // The cid: scheme for cross-part references QByteArray cid = req.url().path().toUtf8(); if (!cid.startsWith("<")) cid = QByteArray("<") + cid; if (!cid.endsWith(">")) cid += ">"; Imap::Mailbox::TreeItemPart *target = cidToPart(cid, model, model->realTreeItem(message)); if (target) { return new Imap::Network::MsgPartNetworkReply(this, target->toIndex(model)); } else { qDebug() << "Content-ID not found" << cid; return new Imap::Network::ForbiddenReply(this); } } else if (req.url() == QUrl(QLatin1String("about:blank"))) { // about:blank is a relatively harmless URL which is used for opening an empty page return QNetworkAccessManager::createRequest(op, req, outgoingData); } else if (req.url().scheme() == QLatin1String("data")) { // data: scheme shall be safe, it's just a method of local access after all return QNetworkAccessManager::createRequest(op, req, outgoingData); } else { // Regular access -- we've got to check policy here if (req.url().scheme() == QLatin1String("http") || req.url().scheme() == QLatin1String("https")) { if (externalsEnabled) { return QNetworkAccessManager::createRequest(op, req, outgoingData); } else { emit requestingExternal(req.url()); return new Imap::Network::ForbiddenReply(this); } } else { qDebug() << "Forbidden per policy:" << req.url(); return new Imap::Network::ForbiddenReply(this); } } }
MessageView::MessageView(QWidget *parent, QSettings *settings): QWidget(parent), m_settings(settings) { QPalette pal = palette(); pal.setColor(backgroundRole(), palette().color(QPalette::Active, QPalette::Base)); pal.setColor(foregroundRole(), palette().color(QPalette::Active, QPalette::Text)); setPalette(pal); setAutoFillBackground(true); setFocusPolicy(Qt::StrongFocus); // not by the wheel netAccess = new Imap::Network::MsgPartNetAccessManager(this); connect(netAccess, SIGNAL(requestingExternal(QUrl)), this, SLOT(externalsRequested(QUrl))); factory = new PartWidgetFactory(netAccess, this); emptyView = new EmbeddedWebView(this, new QNetworkAccessManager(this)); emptyView->setFixedSize(450,300); QMetaObject::invokeMethod(emptyView, "handlePageLoadFinished", Qt::QueuedConnection); emptyView->setPage(new UserAgentWebPage(emptyView)); emptyView->installEventFilter(this); emptyView->setAutoFillBackground(false); viewer = emptyView; //BEGIN create header section headerSection = new QWidget(this); // we create a dummy header, pass it through the style and the use it's color roles so we // know what headers in general look like in the system QHeaderView helpingHeader(Qt::Horizontal); helpingHeader.ensurePolished(); pal = headerSection->palette(); pal.setColor(headerSection->backgroundRole(), palette().color(QPalette::Active, helpingHeader.backgroundRole())); pal.setColor(headerSection->foregroundRole(), palette().color(QPalette::Active, helpingHeader.foregroundRole())); headerSection->setPalette(pal); headerSection->setAutoFillBackground(true); // the actual mail header m_envelope = new EnvelopeView(headerSection, this); // the tag bar tags = new TagListWidget(headerSection); tags->setBackgroundRole(helpingHeader.backgroundRole()); tags->setForegroundRole(helpingHeader.foregroundRole()); tags->hide(); connect(tags, SIGNAL(tagAdded(QString)), this, SLOT(newLabelAction(QString))); connect(tags, SIGNAL(tagRemoved(QString)), this, SLOT(deleteLabelAction(QString))); // whether we allow to load external elements externalElements = new ExternalElementsWidget(this); externalElements->hide(); connect(externalElements, SIGNAL(loadingEnabled()), this, SLOT(externalsEnabled())); // layout the header layout = new QVBoxLayout(headerSection); layout->addWidget(m_envelope, 1); layout->addWidget(tags, 3); layout->addWidget(externalElements, 1); //END create header section //BEGIN layout the message layout = new QVBoxLayout(this); layout->setSpacing(0); layout->setContentsMargins(0,0,0,0); layout->addWidget(headerSection, 1); headerSection->hide(); // put the actual messages into an extra horizontal view // this allows us easy usage of the trailing stretch and also to indent the message a bit QHBoxLayout *hLayout = new QHBoxLayout; hLayout->setContentsMargins(6,6,6,0); hLayout->addWidget(viewer); static_cast<QVBoxLayout*>(layout)->addLayout(hLayout, 1); // add a strong stretch to squeeze header and message to the top // possibly passing a large stretch factor to the message could be enough... layout->addStretch(1000); //END layout the message // make the layout used to add messages our new horizontal layout layout = hLayout; markAsReadTimer = new QTimer(this); markAsReadTimer->setSingleShot(true); connect(markAsReadTimer, SIGNAL(timeout()), this, SLOT(markAsRead())); m_loadingSpinner = new Spinner(this); m_loadingSpinner->setText(tr("Fetching\nMessage")); m_loadingSpinner->setType(Spinner::Sun); }