<|start_filename|>historydatabase.cpp<|end_filename|>
/*
  historydatabase.cpp - implementation of WildFox's HistoryDatabase class.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2013/04/05, <NAME>
  (c) Nyanko.ws
*/



#include <QSqlQuery>
#include <QDateTime>
#include <QStandardPaths>
#include <QDir>
#include <QDebug>
#include <QSqlError>

#include "historydatabase.h"


HistoryDatabase* HistoryDatabase::instance = 0;
QString HistoryDatabase::storagePath;
QSqlDatabase HistoryDatabase::db;
QSqlQueryModel* HistoryDatabase::queryModel;


// --- CONSTRUCTOR ---
HistoryDatabase::HistoryDatabase() {
    // Open the SQLite history database if present. Check its integrity. Recreate
    // a default instance if there are any issues.
    storagePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
    storagePath = QDir::toNativeSeparators(storagePath + "/");
    db = QSqlDatabase::addDatabase("QSQLITE", "historydb");
    db.setDatabaseName(storagePath + "history.sqlite");
    if (!db.open()) {
        qDebug("Failed to open the history database.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
    
    QSqlQuery query(db);
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='history'");
    if (!query.next()) {
        // table doesn't exist, create it.
        query.finish();
        bool err = query.exec(QString("CREATE TABLE history (id INTEGER PRIMARY KEY, ") +
                   QString("url TEXT, title TEXT, visit_count INTEGER, ") +
                   QString("lastModified INTEGER)"));
        if (!err) {
            qDebug("Creating history table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }
        
        query.finish();
        err = query.exec(QString("CREATE INDEX history_url ON history (url)"));
        if (!err) {
            qDebug("Creating url index on history table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }
        
        query.finish();
        err = query.exec(QString("CREATE INDEX history_visitcount ON history (visit_count)"));
        if (!err) {
            qDebug("Creating visitcount index on history table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }
        
        query.finish();
        err = query.exec(QString("CREATE INDEX history_lastmodified ON history (lastModified)"));
        if (!err) {
            qDebug("Creating lastModified index on history table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }
    }
}


// --- DECONSTRUCTOR ---
HistoryDatabase::~HistoryDatabase() {
    db.close();
}


// --- ADD HISTORY ENTRY ---
// Used by Webkit. Adds a new history entry if it doesn't exist yet in the database.
// NOTE: currently not called as this doesn't add a title. New overloaded function
// now being called from main window after load.
void HistoryDatabase::addHistoryEntry(const QString &url) {
    if (historyContains(url)) {
        reportVisit(url);
        return;
    }
    
    qDebug() << "Adding history entry:" << url;
    QSqlQuery query(db);
    query.prepare("INSERT INTO history (url, title, visit_count, lastModified) VALUES (:url, :title, :visit_count, :lastModified)");
    query.bindValue(":url", url);
    query.bindValue(":title", "Unknown");
    query.bindValue(":visit_count", 0);
    query.bindValue(":lastModified", QDateTime::currentDateTime().toTime_t());
    int err = query.exec();
    if (!err) {
        qDebug("Inserting new entry into history table failed.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
}


// --- ADD HISTORY ENTRY ---
// Overloaded function. Adds a new history entry with its page title if it 
// doesn't exist yet in the database.
void HistoryDatabase::addHistoryEntry(const QString &url, const QString &title) {
    if (historyContains(url)) {
        reportVisit(url);
        return;
    }
    
    qDebug() << "Adding history entry:" << url;
    QSqlQuery query(db);
    query.prepare("INSERT INTO history (url, title, visit_count, lastModified) VALUES (:url, :title, :visit_count, :lastModified)");
    query.bindValue(":url", url);
    query.bindValue(":title", title);
    query.bindValue(":visit_count", 0);
    query.bindValue(":lastModified", QDateTime::currentDateTime().toTime_t());
    int err = query.exec();
    if (!err) {
        qDebug("Inserting new entry into history table failed.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
}


// --- HISTORY CONTAINS ---
// Used by Webkit. Returns true if the provided URL exists in the database, 
// otherwise returns false.
bool HistoryDatabase::historyContains(const QString &url) const {
    //qDebug() << "History contains:" << url;
    QSqlQuery query(db);
    query.prepare("SELECT COUNT(*) FROM history WHERE url=:url");
    query.bindValue(":url", url);
    bool err = query.exec();
    if (!err) {
        qDebug("Searching for URL in history table failed.");
        qDebug() << "Cause: " << db.lastError().text();
        return false;
    }
    
    if (query.next()) {
        //qDebug() << "Checking value...";
        if (query.value(0).toInt() > 0) {
            //qDebug() << "True." << query.value(0).toInt();
            return true;
        }
    }
    
    //qDebug() << "False." << query.value(0).toInt();
    return false;
}


// --- REPORT VISIT ---
// Called when a URL is visited. Increases visit count if the item already exists.
void HistoryDatabase::reportVisit(const QString &url) {
    qDebug() << "Reporting visit:" << url;
    QSqlQuery query(db);
    query.prepare("UPDATE history SET visit_count=visit_count + 1 WHERE url=:url AND lastModified=:lastModified");
    query.bindValue(":url", url);
    query.bindValue(":lastModified", QDateTime::currentDateTime().toTime_t());
    bool err = query.exec();
    if (!err) {
        qDebug("Updating visit count for URL in history table failed.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
}


// --- HISTORY OBJECTS MATCHING ---
// Return up to limit objects matching the provided string, sorted by visit count.
void HistoryDatabase::historyObjectsMatching(QString &like, int limit, QList<HistoryObject> &objects) {
    QSqlQuery query(db);
    query.prepare("SELECT url, title FROM history WHERE url LIKE :like ORDER BY visit_count ASC LIMIT :limit");
    query.bindValue(":like", QString("%%1%").arg(like));
    query.bindValue(":limit", limit);
    bool err = query.exec();
    if (!err) {
        qDebug("Finding URL matches in history table failed.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
    
    //QList<HistoryObject> objects;
    HistoryObject object;
    while (query.next()) {
        object.url = query.value(0).toString();
        object.title = query.value(1).toString();
        //qDebug() << "URL: " << object.url;
        objects.append(object);
    }
}


<|start_filename|>cookiejar.cpp<|end_filename|>
/*
  cookiejar.cpp - Cookie Jar implementation file of WildFox.
  
  Revision 0
  
  Features:
        - Implements a network cookie jar with saving/loading feature.
        - Implements third-party cookie blocking.
        
  Notes:
        - Uses semi-passive clearing of expired cookies for now.
        
  2012/02/04, <NAME>
  (c) Nyanko.ws
*/


#include <QSqlQuery>
#include <QSqlError>
#include <QDesktopServices>
#include <QDateTime>


#include "cookiejar.h"
#include "tldutil.h"


// --- CONSTRUCTOR ---
CookieJar::CookieJar() {
    // defaults
    /*storagePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation)
            + "/Nyanko/WildFox";*/
    
    // Open the SQLite cookie database if present. Check its integrity. Recreate
    // a default instance if there are any issues.
    storagePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
    storagePath = QDir::toNativeSeparators(storagePath + "/");
    db = QSqlDatabase::addDatabase("QSQLITE", "cookiesdb");
    db.setDatabaseName(storagePath + "cookies.sqlite");
    if (!db.open()) {
        qDebug("Failed to open the cookies database.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
    
    QSqlQuery query(db);
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='moz_cookies'");
    if (!query.next()) {
        // table doesn't exist, create it.
        query.finish();
        bool err = query.exec(QString("CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, ") +
                   QString("baseDomain TEXT, name TEXT, value TEXT, host TEXT, ") +
                   QString("path TEXT, expiry INTEGER, lastAccessed INTEGER, ") +
                   QString("creationTime INTEGER, isSecure INTEGER, isHttpOnly INTEGER, ") +
                   QString("CONSTRAINT moz_uniqueid UNIQUE (name, host, path))"));
        if (!err) {
            qDebug("Creating cookies table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }
    }
    
    if (!db.isOpen()) {
        qDebug() << "Cookies db is not open!";
    }
}


// --- DECONSTRUCTOR ---
CookieJar::~CookieJar() {
    db.close();
}


// --- COOKIES FOR URL ---
// Returns the list of cookies for a given URL.
QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const {
    //qDebug() << "Sending cookies...";
    // Determine the top domain.    
    QString baseDomain = getPublicDomain(url.host());
    QString pathAndFileName = url.path();
    QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/')) + 1);
    if (defaultPath.isEmpty())
        defaultPath = QLatin1Char('/');
    
    bool isEncrypted = url.scheme().toLower() == QLatin1String("https");
    
    // Load the cookies from the database if not found in the buffer. Select 
    // everything for this base domain, use the base domain as the key for the 
    // multi map and QNetworkCookies as the values.
    QList<QNetworkCookie> result;
    
    // if cookies are disabled in settings, return empty list.
    if (settings.value("cookiesEnabled", true).toBool() == false) { return result; }
    
    QMap<QString, QNetworkCookie>::iterator cookies;
    cookies = cookiebuffer.find(baseDomain);
    //qDebug() << "Searched for base domain in buffer: " << baseDomain;
    if (cookies == cookiebuffer.end()) {
        // not in the buffer, search the database.
        //qDebug() << "Searching database for cookies...";
        QList<QNetworkCookie> temp;
        if (!loadCookies(temp, baseDomain)) {
            //qDebug() << "Nothing found, return empty.";
            return result; // nothing found, return empty list
        }
        
        /*for (int i = 0; i < temp.size(); ++i) {
            if (temp[i].isSecure() != isEncrypted) {
                // Skip this cookie
                //qDebug() << "Skipping due to security mismatch.";
                continue;
            }
            //else if (temp[i].path() != defaultPath) { continue; }
            else { result.append(temp[i]); }
            //qDebug() << "Added cookie to output.";
        }*/
        
        // TODO: sort these cookies and verify on path
        //return result;
    }
        
    // in the buffer, copy it to output list and return
    QList<QNetworkCookie> temp = cookiebuffer.values(baseDomain);
    //qDebug() << "Cookies found in buffer. Copying " << temp.size() << " cookies";
    //qDebug() << "URL host: " << url.host();
    QString urlHost = url.host(); // FIXME: do proper domain verification
    //if (urlHost.startsWith(".")) { urlHost.remove(0, 1); }
    for (int i = 0; i < temp.size(); ++i) {
        // verify the cookies retrieved
        QString cookieDomain = temp[i].domain();
        if (cookieDomain.startsWith(".")) { cookieDomain.remove(0, 1); }
        //qDebug() << cookieDomain << ", " << urlHost << ", secure: " << temp[i].isSecure();
        if (urlHost.endsWith(cookieDomain, Qt::CaseInsensitive) 
                && temp[i].isSecure() <= isEncrypted) { 
                //&& temp[i].path() == defaultPath) {
            // add this cookie
            result.append(temp[i]);
            //qDebug() << "Sending cookie for: " << temp[i].domain(); // << ", host: " << url.host();
            //qDebug() << "Cookie name: " << temp[i].name();
            //qDebug() << "Cookie domain: " << cookieDomain;
            // TODO: verification & sorting
        }
    }
    
    //qDebug() << "Printing cookie list.";
    /*for (int i = 0; i < result.size(); ++i) {
        qDebug() << "Domain: " + result[i].domain() << "name: " + result[i].name() << "value: " + result[i].value();
    }*/
    
    return result;
}


// --- SET COOKIES FROM URL ---
// Adds the cookies in the provided list for the provided URL.
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) {
    // if cookies are disabled in settings, return false.
    if (settings.value("cookiesEnabled", true).toBool() == false) { return false; }
        
    QString defaultDomain = url.host();
    QString pathAndFileName = url.path();
    QString defaultPath = pathAndFileName.left(pathAndFileName.lastIndexOf(QLatin1Char('/'))+1);
    if (defaultPath.isEmpty())
        defaultPath = QLatin1Char('/');
    
    int added = 0;
    bool updated = false;
    QDateTime now = QDateTime::currentDateTime();
    QString baseDomain = getPublicDomain(url.host());
    //qDebug() << "Cookie List size: " << cookieList.size();
    //bool skip3rd = settings.value("cookies3rdDisabled", true).toBool();
    QSqlQuery query(db);
    for (int i = 0; i < cookieList.size(); ++i) {
        updated = false;
        QNetworkCookie cookie = cookieList[i];
        //baseDomain = getPublicDomain(cookie.domain());
        // if 3rd-party cookies are disabled in settings, skip this cookie
        // if its domain doesn't match up with that of the current url.
        //qDebug() << "Skip3rd: " << skip3rd << " | " << baseDomain << ", " << getPublicDomain(cookie.domain());
        /*if (skip3rd && (baseDomain.compare(getPublicDomain(cookie.domain()), Qt::CaseInsensitive) != 0)) {
            qDebug() << "Skipping this cookie.";
            continue;
        }*/
        // FIXME: get 3rd-party blocking working...
        
        //qDebug() << "Cookie name: " << cookie.name();
        /*bool isDeletion = !cookie.isSessionCookie() &&
                cookie.expirationDate() < now;*/
        if (!cookie.isSessionCookie() && cookie.expirationDate() < now) {
            //qDebug() << "Expired: " << cookie.name() << cookie.value();
            continue; // skip this cookie as it's already expired.
        }
        
        // validate the cookie & set the defaults if unset
        if (cookie.path().isEmpty())
            cookie.setPath(defaultPath);
        // don't do path checking. See http://bugreports.qt.nokia.com/browse/QTBUG-5815
        /* else if (!isParentPath(pathAndFileName, cookie.path())) {
                continue;           // not accepted
            }*/
        if (cookie.domain().isEmpty()) {
            cookie.setDomain(defaultDomain);
            if (!cookie.domain().startsWith(QLatin1Char('.')))
                cookie.setDomain(QLatin1Char('.') + cookie.domain());
        } else {
            // Ensure the domain starts with a dot if its field was not empty
            // in the HTTP header. There are some servers that forget the
            // leading dot and this is actually forbidden according to RFC 2109,
            // but all browsers accept it anyway so we do that as well.
            if (!cookie.domain().startsWith(QLatin1Char('.')))
                cookie.setDomain(QLatin1Char('.') + cookie.domain());
            
            QString domain = cookie.domain();
            /*if (!(isParentDomain(domain, defaultDomain)
                  || isParentDomain(defaultDomain, domain)))
                continue; // not accepted*/
            
            // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
            // redundant; the "leading dot" rule has been relaxed anyway, see above
            // we remove the leading dot for this check
            if (isEffectiveTLD(domain.remove(0, 1))) {
                //qDebug() << "TLD, skipping: " << cookie.name() << cookie.value();
                continue; // not accepted
            }
        }
        
        // Check whether this cookie already exists.
        QList<QNetworkCookie> temp;
        QMultiMap<QString, QNetworkCookie>::iterator cit;
        cit = cookiebuffer.find(baseDomain);
        //qDebug() << "Size of CookieBuffer: " << cookiebuffer.size();
        if (cit == cookiebuffer.end()) {
            if (!loadCookies(temp, baseDomain)) {
                // nothing found, insert all provided cookies
                //qDebug() << "No cookies found in database for " << baseDomain;
            }
            else {
                cit = cookiebuffer.find(baseDomain);
                //qDebug() << "Found " << temp.size() << " cookies in database for domain " << baseDomain;
            }
        }
        
        if (cit != cookiebuffer.end()) {
            // we found the base domain in question, next search the cookies in it for a match
            //qDebug() << "Searching for cookies in cookie buffer matching " << cookie.name() << "...";
            while (cit != cookiebuffer.end() && cit.key() == baseDomain) {
                QNetworkCookie c = cit.value();
                //qDebug() << "Cookie name: " << c.name();
                if (c.name() == cookie.name() &&
                        c.domain() == cookie.domain() &&
                        c.path() == cookie.path()) {
                    // same cookie, overwrite it.
                    //qDebug() << "Found cookie match: " << c.name() << " - " << c.value();
                    cit.value() = cookie;
                    updated = true;
                    
                    // update in database too
                    if (cookie.isSessionCookie()) { ++cit; continue; }
                    query.prepare("UPDATE moz_cookies SET value=:value, expiry=" 
                                  + QString::number(cookie.expirationDate().toTime_t())
                                  + ", isSecure=:isSecure, isHttpOnly=:isHttpOnly"
                                  + " WHERE baseDomain=:baseDomain AND host=:host AND path=:path AND name=:name");
                    query.bindValue(":value", cookie.value());
                    query.bindValue(":host", cookie.domain());
                    query.bindValue(":baseDomain", baseDomain);
                    query.bindValue(":path", cookie.path());
                    query.bindValue(":name", cookie.name());
                    query.bindValue(":isSecure", cookie.isSecure());
                    query.bindValue(":isHttpOnly", cookie.isHttpOnly());
                    bool err = query.exec();
                    if (!err) {
                        qDebug() << "Failed to update database with query: " << query.executedQuery();
                        qDebug() << "Cause: " << query.lastError().text();
                        qDebug() << "name: " << cookie.name() << ", host: " << cookie.domain() << ", path: " << cookie.path();
                        ++cit;
                        continue; // continue with next cookie
                    }
                    
                    query.finish();
                    ++added;
                    break;
                }
                
                ++cit;
            }
        }
        
        if (!updated) {
            //qDebug() << "No existing cookie, inserting as new. Name: " << cookie.name();
            //qDebug() << "Session cookie: " << cookie.isSessionCookie();
            cookiebuffer.insert(baseDomain, cookie);
            if (!cookie.isSessionCookie()) {
                uint tstamp = cookie.expirationDate().toTime_t();
                QSqlQuery query(db);
                query.prepare("INSERT INTO moz_cookies (baseDomain, name, value, host, path, expiry, isSecure, isHttpOnly) VALUES (:baseDomain, :name, :value, :host, :path, "
                              + QString::number(tstamp) + ", "
                              + QString(cookie.isSecure()?"1":"0") + ", "
                              + QString(cookie.isHttpOnly()?"1":"0") + ")");
                query.bindValue(":value", cookie.value());
                query.bindValue(":host", cookie.domain());
                query.bindValue(":baseDomain", baseDomain);
                query.bindValue(":path", cookie.path());
                query.bindValue(":name", cookie.name());
                bool err = query.exec();
                if (!err) {
                    qDebug() << "Failed to insert into database with query: " << query.executedQuery();
                    qDebug() << "Cause: " << query.lastError().text();
                    qDebug() << "name: " << cookie.name() << ", host: " << cookie.domain() << ", path: " << cookie.path();
                    continue;
                }
                
                query.finish();
                ++added;
            }
        }
    }
    
    return (added > 0);
}


// --- ALL COOKIES ---
// Returns a list of all the stored cookies.
QList<QNetworkCookie> CookieJar::allCookies() const {
    QList<QNetworkCookie> allCookies;
    return allCookies;
}


// --- SET ALL COOKIES ---
// Replaces the existing list of cookies with the provided list.
void CookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList) {
    //allCookies = cookieList;
    // TODO: fill in this function.
}


// --- GET BUFFER ---
// Return pointer to the cookie buffer.
QMultiMap<QString, QNetworkCookie> *CookieJar::getBuffer() {
    return &cookiebuffer;
}


// --- GET DATABASE ---
// Return a pointer to the cookie database object.
QSqlDatabase* CookieJar::getDatabase() {
    return &db;
}


// --- IS PARENT DOMAIN ---
inline bool CookieJar::isParentDomain(QString domain, QString reference) const {
    if (!reference.startsWith(QLatin1Char('.')))
        return domain == reference;

    return domain.endsWith(reference) || domain == reference.mid(1);
}


// --- LOAD COOKIES ---
// Load cookies for a top domain into the buffer, if any exist.
bool CookieJar::loadCookies(QList<QNetworkCookie> &cookies, QString baseDomain) const {
    //qDebug() << "Load cookies...";
    QSqlQuery query(db);
    query.prepare("SELECT name, value, host, path, expiry, isSecure, isHttpOnly FROM moz_cookies WHERE baseDomain='" + baseDomain + "'");
    bool err = query.exec();
    if (!err) {
        qDebug() << "Failed to fetch cookies from DB: " << query.lastError().text();
        //qDebug() << "Cause: " << query.lastError().text();
        return false;
    }
    else if (query.next()){
        // extract data and assemble into cookies.
        QDateTime now = QDateTime::currentDateTime();
        QDateTime dt;
        do {
            QNetworkCookie cookie;
            cookie.setDomain(query.value(2).toString());
            cookie.setPath(query.value(3).toString());
            cookie.setName(query.value(0).toByteArray());
            //qDebug() << "Cookie fetched: " << cookie.name();
            dt.setTime_t((uint) query.value(4).toULongLong());
            if (dt < now) { 
                //qDebug() << cookie.name() << ": dt: " << dt.toString() << " | now: " << now.toString();
                //qDebug() << "UNIX: " << query.value(4).toInt() << " | " << now.toTime_t();
                // remove this cookie
                QSqlQuery delquery(db);
                delquery.prepare("DELETE FROM moz_cookies WHERE baseDomain=:baseDomain AND path=:path AND name=:name");
                delquery.bindValue(":baseDomain", baseDomain);
                delquery.bindValue(":path", cookie.path());
                delquery.bindValue(":name", cookie.name());
                err = delquery.exec();
                if (!err) {
                    qDebug() << "Failed to delete from database with query: " << delquery.lastQuery();
                    qDebug() << "Cause: " << delquery.lastError().text();
                    continue;
                }
                
                continue; 
            }
            
            cookie.setExpirationDate(dt);
            cookie.setValue(query.value(1).toByteArray());
            cookie.setSecure(query.value(5).toBool());
            cookie.setHttpOnly(query.value(6).toBool());
            
            // insert into buffer and result list.
            cookiebuffer.insert(baseDomain, cookie);
            cookies.append(cookie);
        } while (query.next());
    }
    else {
        // nothing found, return false;
        //qDebug() << "No cookies found for " << baseDomain << ".";
        return false;
    }
    
    return true;
}


<|start_filename|>iofile.cpp<|end_filename|>
/*
  iofile.cpp - IO File implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/

#include "iofile.h"

#include <QDebug>


// --- SET NETWORK REPLY ---
// Set the QNetworkReply instance to use.
void IOFile::setNetworkReply(QNetworkReply* reply) {
    this->reply = reply;
}


// --- READ PROGRESS ---
// Connected to IODevice's progress indicator. Returns a percentage of total
// as a signal.
void IOFile::readProgress(qint64 current, qint64 total) {
    int percentage = ((double) current) / ((double) total) * 100;
    emit progress(percentage);
}


// --- READ FROM REPLY ---
// Called when the QNetworkReply has new data available.
// Read new data from the QNetworkReply instance and write it to the open file.
void IOFile::readFromReply() {
    qDebug() << "Reading from reply...";
    if (!isOpen()) { return; }
    
    qDebug() << "Reading...";
    qDebug() << "Bytes:" << reply->bytesAvailable();
    write(reply->readAll());
    
    /*char* bytes = new char[4096];
    qint64 count = reply->read(bytes, 4096);
    if (count == 0) {
        qDebug() << "No more data available.";
        return;
    }
    else if (count < 0) {
        qDebug() << "An error occurred on the Reply socket.";
        return;
    }
    
    qDebug() << "Writing...";
    //while (reply->bytesAvailable() > 0) {
        write(bytes, count);
   // }*/
}


// --- CANCEL ---
// Cancel the current transfer and clean up resources.
void IOFile::cancel() {
    reply->abort();
    reply->close();
    terminate();
}


// --- TERMINATE ---
// Shut down, clean up resources.
void IOFile::terminate() {
    if (isOpen()) {
        close();
    }
    
    deleteLater();
}


<|start_filename|>addressbareventfilter.h<|end_filename|>
/*
  addressbareventfilter.h - addressBarEventFilter class header file of WildFox.

  Revision 0

  Notes:
        -

  2013/04/25, <NAME>
  (c) Nyanko.ws
*/


#ifndef ADDRESSBAREVENTFILTER_H
#define ADDRESSBAREVENTFILTER_H

#include <QObject>

class addressBarEventFilter : public QObject
{
    Q_OBJECT
public:
    explicit addressBarEventFilter(QObject *parent = 0);
    
    bool eventFilter(QObject *, QEvent *);
    
signals:
    void addressBarPopup();
    
public slots:
    
};

#endif // ADDRESSBAREVENTFILTER_H


<|start_filename|>tldutil.cpp<|end_filename|>
/*
  tldutil.cpp - URL Top Level Domain utility implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - Allows one to check whether a provided domain is a public suffix,
            i.e. not a .com, .co.uk or similar non-public domain.
        
  Notes:
        - Modified from the original Qt implementation.
        
  2012/02/07, <NAME>
  (c) Nyanko.ws
*/


#include "tldutil.h"
#include "qurltlds_p.h"

#include <QtCore>


// --- CONTAINS TLD ENTRY ---
// Returns true if the entry has been found in the TLD list.
static bool containsTLDEntry(const QString &entry) {
    int index = qHash(entry) % tldCount;
    int currentDomainIndex = tldIndices[index];
    while (currentDomainIndex < tldIndices[index+1]) {
        QString currentEntry = QString::fromUtf8(tldData + currentDomainIndex);
        if (currentEntry == entry)
            return true;
        currentDomainIndex += qstrlen(tldData + currentDomainIndex) + 1; // +1 for the ending \0
    }
    return false;
}


// --- IS EFFECTIVE TLD ---
// Return true if provided domain is a top-level-domain per the Mozilla 
// public suffix list.
bool isEffectiveTLD(const QString &domain) {
    // for domain 'foo.bar.com':
    // 1. return if TLD table contains 'foo.bar.com'
    if (containsTLDEntry(domain))
        return true;

    if (domain.contains(QLatin1Char('.'))) {
        int count = domain.size() - domain.indexOf(QLatin1Char('.'));
        QString wildCardDomain;
        wildCardDomain.reserve(count + 1);
        wildCardDomain.append(QLatin1Char('*'));
        wildCardDomain.append(domain.right(count));
        // 2. if table contains '*.bar.com',
        // test if table contains '!foo.bar.com'
        if (containsTLDEntry(wildCardDomain)) {
            QString exceptionDomain;
            exceptionDomain.reserve(domain.size() + 1);
            exceptionDomain.append(QLatin1Char('!'));
            exceptionDomain.append(domain);
            return (! containsTLDEntry(exceptionDomain));
        }
    }
    return false;
}


// --- GET PUBLIC DOMAIN ---
// Reduce a URL until only only the non-public part remains (e.g. .com and .co.uk)
// Return it and the first public section preceding it.
QString getPublicDomain(const QString &domain) {
    QStringList sections = domain.toLower().split(QLatin1Char('.'), QString::SkipEmptyParts);
    if (sections.isEmpty() || sections.size() <= 1)
        return QString();
    
    QString tld = "";
    for (int i = sections.count() - 1; i >= 0; --i) {
        tld.prepend(QLatin1Char('.') + sections.at(i));
        if (!isEffectiveTLD(tld.right(tld.size() - 1))) {
            tld = '.' + sections.at(i - 1) + tld;
            return tld;
        }
    }
    
    return tld;
}


// --- TOP LEVEL DOMAIN ---
QString topLevelDomain(const QString &domain) {
    QStringList sections = domain.toLower().split(QLatin1Char('.'), QString::SkipEmptyParts);
    if (sections.isEmpty())
        return QString();

    QString level, tld;
    for (int j = sections.count() - 1; j >= 0; --j) {
        level.prepend(QLatin1Char('.') + sections.at(j));
        if (isEffectiveTLD(level.right(level.size() - 1)))
            tld = level;
    }
    return tld;
}


<|start_filename|>wfwebhistoryinterface.h<|end_filename|>
/*
  wfwebhistoryinterface.h - declaration of WildFox's WFWebHistoryInterface class.
  
  Revision 0
        
  Notes:
        - 
        
  2013/04/04, <NAME>
  (c) Nyanko.ws
*/


#ifndef WFWEBHISTORYINTERFACE_H
#define WFWEBHISTORYINTERFACE_H

#include <QWebHistoryInterface>

#include "historydatabase.h"

class WFWebHistoryInterface : public QWebHistoryInterface
{
    Q_OBJECT
public:
    explicit WFWebHistoryInterface();
    
    void addHistoryEntry(const QString &url);
    bool historyContains(const QString &url) const;
    
signals:
    
public slots:
    
private:
    HistoryDatabase* history;
};

#endif // WFWEBHISTORYINTERFACE_H


<|start_filename|>json.h<|end_filename|>
/* Copyright 2011 <NAME>. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
 * EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation 
 * are those of the authors and should not be interpreted as representing 
 * official policies, either expressed or implied, of Eeli Reilin.
 */

/**
 * \file json.h
 */

#ifndef JSON_H
#define JSON_H

#include <QVariant>
#include <QString>

namespace QtJson
{

/**
 * \enum JsonToken
 */
enum JsonToken
{
        JsonTokenNone = 0,
        JsonTokenCurlyOpen = 1,
        JsonTokenCurlyClose = 2,
        JsonTokenSquaredOpen = 3,
        JsonTokenSquaredClose = 4,
        JsonTokenColon = 5,
        JsonTokenComma = 6,
        JsonTokenString = 7,
        JsonTokenNumber = 8,
        JsonTokenTrue = 9,
        JsonTokenFalse = 10,
        JsonTokenNull = 11
};

/**
 * \class Json
 * \brief A JSON data parser
 *
 * Json parses a JSON data into a QVariant hierarchy.
 */
class Json
{
        public:
                /**
                 * Parse a JSON string
                 *
                 * \param json The JSON data
                 */
                static QVariant parse(const QString &json);

                /**
                 * Parse a JSON string
                 *
                 * \param json The JSON data
                 * \param success The success of the parsing
                 */
                static QVariant parse(const QString &json, bool &success);

                /**
                * This method generates a textual JSON representation
                *
                * \param data The JSON data generated by the parser.
                * \param success The success of the serialization
                */
                static QByteArray serialize(const QVariant &data);

                /**
                * This method generates a textual JSON representation
                *
                * \param data The JSON data generated by the parser.
                * \param success The success of the serialization
                *
                * \return QByteArray Textual JSON representation
                */
                static QByteArray serialize(const QVariant &data, bool &success);

        private:
                /**
                 * Parses a value starting from index
                 *
                 * \param json The JSON data
                 * \param index The start index
                 * \param success The success of the parse process
                 *
                 * \return QVariant The parsed value
                 */
                static QVariant parseValue(const QString &json, int &index,
                                                                   bool &success);

                /**
                 * Parses an object starting from index
                 *
                 * \param json The JSON data
                 * \param index The start index
                 * \param success The success of the object parse
                 *
                 * \return QVariant The parsed object map
                 */
                static QVariant parseObject(const QString &json, int &index,
                                                                           bool &success);

                /**
                 * Parses an array starting from index
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 * \param success The success of the array parse
                 *
                 * \return QVariant The parsed variant array
                 */
                static QVariant parseArray(const QString &json, int &index,
                                                                           bool &success);

                /**
                 * Parses a string starting from index
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 * \param success The success of the string parse
                 *
                 * \return QVariant The parsed string
                 */
                static QVariant parseString(const QString &json, int &index,
                                                                        bool &success);

                /**
                 * Parses a number starting from index
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 *
                 * \return QVariant The parsed number
                 */
                static QVariant parseNumber(const QString &json, int &index);

                /**
                 * Get the last index of a number starting from index
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 *
                 * \return The last index of the number
                 */
                static int lastIndexOfNumber(const QString &json, int index);

                /**
                 * Skip unwanted whitespace symbols starting from index
                 *
                 * \param json The JSON data
                 * \param index The start index
                 */
                static void eatWhitespace(const QString &json, int &index);

                /**
                 * Check what token lies ahead
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 *
                 * \return int The upcoming token
                 */
                static int lookAhead(const QString &json, int index);

                /**
                 * Get the next JSON token
                 *
                 * \param json The JSON data
                 * \param index The starting index
                 *
                 * \return int The next JSON token
                 */
                static int nextToken(const QString &json, int &index);
};


} //end namespace

#endif //JSON_H


<|start_filename|>optionsdialog.cpp<|end_filename|>
/*
  optionsdialog.cpp - Options Dialog implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2021/02/02, <NAME>
  (c) Nyanko.ws
*/


#include "optionsdialog.h"
#include "cookiemanagedialog.h"


// --- CONSTRUCTOR ---
OptionsDialog::OptionsDialog(CookieJar* cookiejar) {
    dialog.setupUi(this);
    
    cookies = cookiejar;
    
    // connections
    connect(dialog.optOkButton, SIGNAL(pressed()), this, SLOT(saveSettings()));
    connect(dialog.optCancelButton, SIGNAL(pressed()), this, SLOT(cancel()));
    connect(dialog.optButtonManageCookies, SIGNAL(pressed()), this, SLOT(manageCookies()));
    
    // load the current settings into the dialogue.
    // General tab
    
    // Privacy tab
    dialog.optCheckEnableCookies->setChecked(settings.value("cookiesEnabled", true).toBool());
    dialog.optCheckDisable3rdCookies->setChecked(settings.value("cookies3rdDisabled", true).toBool());
}


// --- DECONSTRUCTOR ---
OptionsDialog::~OptionsDialog() {
    settings.sync();
}


// --- MANAGE COOKIES ---
// Launches the manage cookies dialogue.
void OptionsDialog::manageCookies() {
    CookieManageDialog cmd(cookies->getDatabase(), cookies->getBuffer());
    cmd.exec();
}


// --- SAVE SETTINGS ---
// Saves the settings and closes the dialogue.
void OptionsDialog::saveSettings() {
    settings.setValue("cookiesEnabled", QVariant(dialog.optCheckEnableCookies->isChecked()));
    settings.setValue("cookies3rdEnabled", QVariant(!dialog.optCheckDisable3rdCookies->isChecked()));
    close();
}


// --- CANCEL ---
// Called when the dialogue is cancelled. No settings are saved. 
// Dialogue is closed.
void OptionsDialog::cancel() {
    close();
}


<|start_filename|>historydialog.cpp<|end_filename|>
/*
  historydialog.cpp - Definition of HistoryDialog class.
  
  Revision 0
  
  Features:
        - 
  
  Notes:
        - 
        
  2013/05/16, <NAME>
  (c) Nyanko.ws
*/


#include <QDebug>

#include "historydialog.h"
#include "ui_historydialog.h"


// --- CONSTRUCTOR ---
HistoryDialog::HistoryDialog(QString *url, QWidget *parent) : QDialog(parent),
    ui(new Ui::HistoryDialog) {
    ui->setupUi(this);
    
    historydb = HistoryDatabase::getInstance();
    this->url = url;
    
    // connections
    connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accepted()));
    connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    connect(ui->addressBar, SIGNAL(textEdited(QString)), 
            this, SLOT(editingTriggered(QString)));
    connect(ui->historyList, SIGNAL(itemActivated(QListWidgetItem*)),
            this, SLOT(itemActivated(QListWidgetItem*)));
}


// --- DECONSTRUCTOR ---
HistoryDialog::~HistoryDialog() {
    delete ui;
}


// --- EDITING TRIGGERED ---
// When the contents of the address bar are being changed by the user this slot
// gets called. Use the address bar contents to search for matches in the history
// database and present them in the history list (QLineWidget).
void HistoryDialog::editingTriggered(QString text) {
    if (text.size() < 3) { return; }
    QString like = text;
    objects.clear();
    historydb->historyObjectsMatching(like, 25, objects);
    ui->historyList->clear();
    
    int objects_size = objects.size();
    qDebug() << "objects: " << objects_size;
    QListWidgetItem* item = 0;
    for (int i = 0; i < objects_size; ++i) {
        //qDebug() << "i: " << i;
        //qDebug() << "qcombobox count: " << ui->addressBar->count();
        //qDebug() << "url: " << objects[i].url;
        //qDebug() << "title: " << objects[i].title;
        item = new QListWidgetItem();
        item->setText(objects[i].title + " - " + objects[i].url);
        item->setData(Qt::UserRole, objects[i].url);
        ui->historyList->addItem(item);
    }
}


// --- ACCEPTED ---
// Ensures the current URL is saved, if any, before calling accept().
void HistoryDialog::accepted() {
    *url = ui->historyList->selectedItems()[0]->data(Qt::UserRole).toString();
    accept();
}


// --- ITEM ACTIVATED ---
// Called when an item in the history list gets activated.
void HistoryDialog::itemActivated(QListWidgetItem* item) {
    *url = item->data(Qt::UserRole).toString();
    accept();
}


<|start_filename|>wfwebpage.cpp<|end_filename|>
/*
  wfwebpage.cpp - implementation of WildFox's WFWebPage class.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2013/03/26, <NAME>
  (c) Nyanko.ws
*/


#include "wfwebpage.h"

#include "QNetworkReply"


// --- CONSTRUCTOR ---
WFWebPage::WFWebPage(QWidget *parent) : QWebPage(parent) {
    //
}


// --- SUPPORTS EXTENSION ---
// Returns whether a certain extension is supported or not.
bool WFWebPage::supportsExtension(Extension extension) const {
    if (extension == ErrorPageExtension) {
        return true;
    }
    
    return false;
}


// --- EXTENSION ---
bool WFWebPage::extension(Extension extension, const ExtensionOption* option, ExtensionReturn* output) {
    if (extension == QWebPage::ErrorPageExtension) {
        // handle the received error.
        ErrorPageExtensionOption* extOption = (ErrorPageExtensionOption*) option;
        int errDomain = extOption->domain;
        int errValue = extOption->error;
        QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
        QString errorHeader = "<html><head><title>Failed loading page</title></head><body>";
        QString errorFooter = "</body></html>";
       //errorPage->content = QString("<html><head><title>Failed loading page</title></head><body>%1</body></html>").arg(info->errorString).toUtf8();
       //return true;
        //int httpResponse = 
        switch (errDomain) {
        case QtNetwork:
            // The error occurred in the QtNetwork layer; 
            // the error code is of type QNetworkReply::NetworkError.
            switch (errValue) {
            case QNetworkReply::NoError:
                // 0    no error condition. Note: When the HTTP protocol returns 
                //      a redirect no error will be reported. You can check if  
                //      there is a redirect with the 
                //      QNetworkRequest::RedirectionTargetAttribute attribute.
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ConnectionRefusedError:
                // 1	the remote server refused the connection 
                //      (the server is not accepting requests)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::RemoteHostClosedError:
                // 2	the remote server closed the connection prematurely, 
                //      before the entire reply was received and processed
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::HostNotFoundError:
                // 3	the remote host name was not found (invalid hostname)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::TimeoutError:
                // 4	the connection to the remote server timed out
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::OperationCanceledError:
                // 5	the operation was canceled via calls to abort() or 
                //      close() before it was finished.
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::SslHandshakeFailedError:
                // 6	the SSL/TLS handshake failed and the encrypted channel 
                //      could not be established. The sslErrors() signal should 
                //      have been emitted.
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::TemporaryNetworkFailureError:
                // 7	the connection was broken due to disconnection from the 
                //      network, however the system has initiated roaming to 
                //      another access point. The request should be resubmitted 
                //      and will be processed as soon as the connection is 
                //      re-established.
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProxyConnectionRefusedError:
                // 101	the connection to the proxy server was refused 
                //      (the proxy server is not accepting requests)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProxyConnectionClosedError:
                // 102	the proxy server closed the connection prematurely, 
                //      before the entire reply was received and processed
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProxyNotFoundError:
                // 103	the proxy host name was not found (invalid proxy hostname)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProxyTimeoutError:
                // 104	the connection to the proxy timed out or the proxy did 
                //      not reply in time to the request sent
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProxyAuthenticationRequiredError:
                // 105	the proxy requires authentication in order to honour the 
                //      request but did not accept any credentials offered (if any)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ContentAccessDenied:
                // 201	the access to the remote content was denied (similar to 
                //      HTTP error 401)
                //errorPage->content(errorHeader + extOption->errorString + errorFooter);
                //return true;
                break;
            case QNetworkReply::ContentOperationNotPermittedError:
                // 202	the operation requested on the remote content is not permitted
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::ContentNotFoundError:
                // 203	the remote content was not found at the server (similar 
                //      to HTTP error 404)
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::AuthenticationRequiredError:
                // 204	the remote server requires authentication to serve the 
                //      content but the credentials provided were not accepted (if any)
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::ContentReSendError:
                // 205	the request needed to be sent again, but this failed for 
                //      example because the upload data could not be read a second time.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProtocolUnknownError:
                // 301	the Network Access API cannot honor the request because 
                //      the protocol is not known
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProtocolInvalidOperationError:
                // 302	the requested operation is invalid for this protocol
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::UnknownNetworkError:
                // 99	an unknown network-related error was detected
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::UnknownProxyError:
                // 199	an unknown proxy-related error was detected
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::UnknownContentError:
                // 299	an unknown error related to the remote content was detected
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case QNetworkReply::ProtocolFailure:
                // 399	a breakdown in protocol was detected (parsing error, 
                //      invalid or unexpected responses, etc.)
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            default:
                //
                break;
            }
            
            break;
        case Http:
            // The error occurred in the HTTP layer; 
            // the error code is a HTTP status code (see QNetworkRequest::HttpStatusCodeAttribute).
            //int httpResponse = 
            switch (errValue) {
            case 400:
                // Bad Request
                // The request cannot be fulfilled due to bad syntax.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 401:
                // Unauthorized
                // Similar to 403 Forbidden, but specifically for use when 
                // authentication is required and has failed or has not yet been 
                // provided.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 402:
                // Payment Required
                // Reserved for future use.[2] The original intention was that 
                // this code might be used as part of some form of digital cash 
                // or micropayment scheme, but that has not happened, and this 
                // code is not usually used. As an example of its use, however, 
                // Apple's defunct MobileMe service generated a 402 error if the 
                // MobileMe account was delinquent. In addition, YouTube uses 
                // this status if a particular IP address has made excessive 
                // requests, and requires the person to enter a CAPTCHA.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 403:
                // Forbidden
                // The request was a valid request, but the server is refusing 
                // to respond to it. Unlike a 401 Unauthorized response, 
                // authenticating will make no difference. On servers where 
                // authentication is required, this commonly means that the 
                // provided credentials were successfully authenticated but that 
                // the credentials still do not grant the client permission 
                // to access the resource.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 404:
                // Not Found
                // The requested resource could not be found but may be 
                // available again in the future. Subsequent requests by the 
                // client are permissible.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 405:
                // Method Not Allowed
                // A request was made of a resource using a request method not 
                // supported by that resource; for example, using GET on a form 
                // which requires data to be presented via POST, or using PUT on 
                // a read-only resource.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 406:
                // Not Acceptable
                // The requested resource is only capable of generating content 
                // not acceptable according to the Accept headers sent in the 
                // request.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 407:
                // Proxy Authentication Required
                // The client must first authenticate itself with the proxy.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 408:
                // Request Timeout
                // The server timed out waiting for the request. According to W3 
                // HTTP specifications: "The client did not produce a request 
                // within the time that the server was prepared to wait. The 
                // client MAY repeat the request without modifications at any 
                // later time."
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 409:
                // Conflict
                // Indicates that the request could not be processed because of 
                // conflict in the request, such as an edit conflict.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 410:
                // Gone
                // Indicates that the resource requested is no longer available 
                // and will not be available again. This should be used when a 
                // resource has been intentionally removed and the resource 
                // should be purged. Upon receiving a 410 status code, the 
                // client should not request the resource again in the future. 
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 411:
                // Length Required
                // The request did not specify the length of its content, which 
                // is required by the requested resource.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 412:
                // Precondition Failed
                // The server does not meet one of the preconditions that the 
                // requester put on the request.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 413:
                // Request Entity Too Large
                // The request is larger than the server is willing or able to 
                // process.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 414:
                // Request-URI Too Long
                // The URI provided was too long for the server to process.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 415:
                // Unsupported Media Type
                // The request entity has a media type which the server or 
                // resource does not support. For example, the client uploads an 
                // image as image/svg+xml, but the server requires that images 
                // use a different format.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 416:
                // Requested Range Not Satisfiable
                // The client has asked for a portion of the file, but the server 
                // cannot supply that portion. For example, if the client asked 
                // for a part of the file that lies beyond the end of the file.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 417:
                // Expectation Failed
                // The server cannot meet the requirements of the Expect 
                // request-header field.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 418:
                // I'm a teapot (RFC 2324)
                // This code was defined in 1998 as one of the traditional IETF 
                // April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control 
                // Protocol, and is not expected to be implemented by actual 
                // HTTP servers.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 420:
                // Enhance Your Calm (Twitter)
                // Not part of the HTTP standard, but returned by the Twitter 
                // Search and Trends API when the client is being rate limited.
                // Other services may wish to implement the 429 Too Many 
                // Requests response code instead.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 422:
                // Unprocessable Entity (WebDAV; RFC 4918)
                // The request was well-formed but was unable to be followed due to semantic errors.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 423:
                // Locked (WebDAV; RFC 4918)
                // The resource that is being accessed is locked.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 424:
                // Failed Dependency (WebDAV; RFC 4918)
                // The request failed due to failure of a previous request 
                // (e.g. a PROPPATCH).
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 425:
                // Unordered Collection (Internet draft)
                // Defined in drafts of "WebDAV Advanced Collections Protocol",
                // but not present in "Web Distributed Authoring and Versioning 
                // (WebDAV) Ordered Collections Protocol".
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 426:
                // Upgrade Required (RFC 2817)
                // The client should switch to a different protocol such as 
                // TLS/1.0.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 428:
                // Precondition Required (RFC 6585)
                // The origin server requires the request to be conditional. 
                // Intended to prevent "the 'lost update' problem, where a 
                // client GETs a resource's state, modifies it, and PUTs it back 
                // to the server, when meanwhile a third party has modified the 
                // state on the server, leading to a conflict."
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 429:
                // Too Many Requests (RFC 6585)
                // The user has sent too many requests in a given amount of time. 
                // Intended for use with rate limiting schemes.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 431:
                // Request Header Fields Too Large (RFC 6585)
                // The server is unwilling to process the request because either 
                // an individual header field, or all the header fields 
                // collectively, are too large.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 449:
                // Retry With (Microsoft)
                // A Microsoft extension. The request should be retried after 
                // performing the appropriate action.
                // Often search-engines or custom applications will ignore 
                // required parameters. Where no default action is appropriate, 
                // the Aviongoo website sends a "HTTP/1.1 449 Retry with valid 
                // parameters: param1, param2, . . ." response. The applications 
                // may choose to learn, or not.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 450:
                // Blocked by Windows Parental Controls (Microsoft)
                // A Microsoft extension. This error is given when Windows 
                // Parental Controls are turned on and are blocking access to 
                // the given webpage.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 451:
                // Parameter Not Understood (RTSP)
                // The recipient of the request does not support one or more 
                // parameters contained in the request.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 452:
                // Conference Not Found (RTSP)
                // The conference indicated by a Conference header field is 
                // unknown to the media server.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 453:
                // Not Enough Bandwidth (RTSP)
                // The request was refused because there was insufficient 
                // bandwidth. This may, for example, be the result of a resource 
                // reservation failure.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 454:
                // Session Not Found (RTSP)
                // The RTSP session identifier in the Session header is missing, 
                // invalid, or has timed out.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 455:
                // Method Not Valid in This State (RTSP)
                // The client or server cannot process this request in its 
                // current state. The response SHOULD contain an Allow header to 
                // make error recovery easier.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 456:
                // Header Field Not Valid for Resource (RTSP)
                // The server could not act on a required request header. For 
                // example, if PLAY contains the Range header field but the 
                // stream does not allow seeking.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 457:
                // Invalid Range (RTSP)
                // The Range value given is out of bounds, e.g., beyond the end 
                // of the presentation.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 458:
                // Parameter Is Read-Only (RTSP)
                // The parameter to be set by SET_PARAMETER can be read but not 
                // modified.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 459:
                // Aggregate Operation Not Allowed (RTSP)
                // The requested method may not be applied on the URL in question 
                // since it is an aggregate (presentation) URL. The method may 
                // be applied on a stream URL.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 460:
                // Only Aggregate Operation Allowed (RTSP)
                // The requested method may not be applied on the URL in question 
                // since it is not an aggregate (presentation) URL. The method 
                // may be applied on the presentation URL.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 461:
                // Unsupported Transport (RTSP)
                // The Transport field did not contain a supported transport 
                // specification.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 462:
                // Destination Unreachable (RTSP)
                // The data transmission channel could not be established 
                // because the client address could not be reached. This error 
                // will most likely be the result of a client attempt to place 
                // an invalid Destination parameter in the Transport field.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 500:
                // Internal Server Error
                // A generic error message, given when no more specific message 
                // is suitable.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 501:
                // Not Implemented
                // The server either does not recognize the request method, or 
                // it lacks the ability to fulfill the request.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 502:
                // Bad Gateway
                // The server was acting as a gateway or proxy and received an 
                // invalid response from the upstream server.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 503:
                // Service Unavailable
                // The server is currently unavailable (because it is overloaded 
                // or down for maintenance). Generally, this is a temporary state.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 504:
                // Gateway Timeout
                // The server was acting as a gateway or proxy and did not 
                // receive a timely response from the upstream server.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 505:
                // HTTP Version Not Supported
                // The server does not support the HTTP protocol version used in 
                // the request.
                //errorPage->content(errorHeader + extOption->errorString.toUtf8() + errorFooter);
                //return true;
                break;
            case 506:
                // Variant Also Negotiates (RFC 2295)
                // Transparent content negotiation for the request results in a 
                // circular reference.
                //
                break;
            case 507:
                // Insufficient Storage (WebDAV; RFC 4918)
                // The server is unable to store the representation needed to 
                // complete the request.
                //
                break;
            case 508:
                // Loop Detected (WebDAV; RFC 5842)
                // The server detected an infinite loop while processing the 
                // request (sent in lieu of 208).
                //
                break;
            case 509:
                // Bandwidth Limit Exceeded (Apache bw/limited extension)
                // This status code, while used by many servers, is not 
                // specified in any RFCs.
                //
                break;
            case 510:
                // Not Extended (RFC 2774)
                // Further extensions to the request are required for the server 
                // to fulfill it.
                //
                break;
            case 511:
                // Network Authentication Required (RFC 6585)
                // The client needs to authenticate to gain network access. 
                // Intended for use by intercepting proxies used to control 
                // access to the network (e.g. "captive portals" used to require 
                // agreement to Terms of Service before granting full Internet 
                // access via a Wi-Fi hotspot).
                //
                break;
            case 550:
                // Permission denied
                //
                break;
            case 551:
                // Option not supported (RTSP)
                // An option given in the Require or the Proxy-Require fields 
                // was not supported. The Unsupported header should be returned 
                // stating the option for which there is no support.
                //
                break;
            case 598:
                // Network read timeout error (Unknown)
                // This status code is not specified in any RFCs, but is used by 
                // Microsoft HTTP proxies to signal a network read timeout 
                //behind the proxy to a client in front of the proxy.
                //
                break;
            case 599:
                // Network connect timeout error (Unknown)
                // This status code is not specified in any RFCs, but is used 
                // by Microsoft HTTP proxies to signal a network connect timeout 
                // behind the proxy to a client in front of the proxy.
                //
                break;
            default:
                break;
            }
            
            break;
        case WebKit:
            // The error is an internal WebKit error.
            //
            break;
        default:            
            //
            break;
        }
        
        errorPage->content = QString(errorHeader + extOption->errorString + errorFooter).toLatin1();
        return true;
    }
    
    return false;
}


<|start_filename|>addressbarcompleter.h<|end_filename|>
/*
  addressbarcompleter.h - declaration of the address bar completer class.
  
  Revision 0
  
  Notes:
        - 
        
  2013/05/18, <NAME>
  (c) Nyanko.ws
*/

#ifndef ADDRESSBARCOMPLETER_H
#define ADDRESSBARCOMPLETER_H

#include <QCompleter>

class AddressBarCompleter : public QCompleter
{
    Q_OBJECT
public:
    explicit AddressBarCompleter(QObject *parent = 0);
    
    void setCompletionPrefix(const QString &prefix);
    
signals:
    
public slots:
    
};

#endif // ADDRESSBARCOMPLETER_H


<|start_filename|>types.h<|end_filename|>

#ifndef TYPES_H
#define TYPES_H


struct Filter {
    int extId;                  // ID of the extension page object, if any.
    QString scheme;             // Used scheme (HTTP or HTTPS)
    QList<QString> segments;    // URL string split on dots.
    QList<QString> scripts;     // paths to the scripts to be included in source.
};


#endif // TYPES_H


<|start_filename|>optionsdialog.h<|end_filename|>
/*
  optionsdialog.h - Options Dialog definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2012/02/02, <NAME>
  (c) Nyanko.ws
*/


#ifndef OPTIONSDIALOG_H
#define OPTIONSDIALOG_H

#include "ui_optionsdialog.h"
#include <QDialog>
#include <QSettings>
#include <QSqlDatabase>

#include "cookiejar.h"

class OptionsDialog : public QDialog {
    Q_OBJECT
    
public:
    OptionsDialog(CookieJar* cookiejar);
    ~OptionsDialog();
    
public slots:
    void manageCookies();
    void saveSettings();
    void cancel();
    
private:
    Ui::OptionsDialog dialog;
    QSettings settings;
    CookieJar* cookies;
};

#endif // OPTIONSDIALOG_H


<|start_filename|>cookiejar.h<|end_filename|>
/*
  cookiejar.h - Cookie Jar definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2012/02/04, <NAME>
  (c) Nyanko.ws
*/


#ifndef COOKIEJAR_H
#define COOKIEJAR_H

#include <QNetworkCookieJar>
#include <QNetworkCookie>
#include <QSqlDatabase>
#include <QMultiMap>
#include <QSettings>
//#include <QDateTime>

/*struct Cookie {
    QString domain;
    QDateTime expiry;
    bool isHttpOnly;
    bool isSecure();
    bool isSessionCookie();
    QByteArray name;
    QString path;
    QByteArray value;
};*/

// --- COOKIE JAR ---
// Reimplementation of the QNetworkCookieJar class.
class CookieJar : public QNetworkCookieJar {
    Q_OBJECT
    
public:
    CookieJar();
    ~CookieJar();
    QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
    bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
    QMultiMap<QString, QNetworkCookie>* getBuffer();
    QSqlDatabase* getDatabase();
    
protected:
    QList<QNetworkCookie> allCookies() const;
    void setAllCookies(const QList<QNetworkCookie> &cookieList);
    
private:
    inline bool isParentDomain(QString domain, QString reference) const;
    bool loadCookies(QList<QNetworkCookie> &cookies, QString baseDomain) const;
    
    QSqlDatabase db;
    QString storagePath;
    mutable QMultiMap<QString, QNetworkCookie> cookiebuffer;
    QSettings settings;
};

#endif // COOKIEJAR_H


<|start_filename|>historydatabase.h<|end_filename|>
/*
  historydatabase.h - declaration of WildFox's HistoryDatabase class.
  
  Revision 0
        
  Notes:
        - 
        
  2013/04/05, <NAME>
  (c) Nyanko.ws
*/


#ifndef HISTORYDATABASE_H
#define HISTORYDATABASE_H

#include <QSqlDatabase>
#include <QSqlQueryModel>


struct HistoryObject {
    QString url;
    QString title;
};


class HistoryDatabase {
public:
    static HistoryDatabase* getInstance() {
        if (instance == 0) {
            instance = new HistoryDatabase();
        }
        
        return instance;
    }
    
    void addHistoryEntry(const QString &url);
    void addHistoryEntry(const QString &url, const QString &title);
    bool historyContains(const QString &url) const;
    void reportVisit(const QString &url);
    void reportVisitAndTitle(const QString &url, const QString title);
    void historyObjectsMatching(QString &like, int limit, QList<HistoryObject> &objects);
    
    static QSqlDatabase db;
    
protected:
    
private:  
    HistoryDatabase();
    ~HistoryDatabase();  
    
    static HistoryDatabase* instance;
    //static HistoryDatabase instance;
    static QString storagePath;
    static QSqlQueryModel* queryModel;
};

#endif // HISTORYDATABASE_H


<|start_filename|>addressbardelegate.h<|end_filename|>
/*
  addressbardelegate.h - Address Bar Delegate declaration file of WildFox.
  
  Revision 0
        
  Notes:
        - 
        
  2013/04/28, <NAME>
  (c) Nyanko.ws
*/


#ifndef ADDRESSBARDELEGATE_H
#define ADDRESSBARDELEGATE_H

#include <QStyledItemDelegate>

class AddressBarDelegate : public QStyledItemDelegate {
    Q_OBJECT
public:
    explicit AddressBarDelegate(QObject *parent = 0);
    
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    
signals:
    
public slots:
    
};

#endif // ADDRESSBARDELEGATE_H


<|start_filename|>mainwindow.h<|end_filename|>
/*
  mainwindow.h - Main definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "ui_mainwindow.h"

#include <QMainWindow>
#include <QDir>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkCookieJar>
#include <QWebFrame>
#include <QWebPage>
#include <QSettings>
#include <QMessageBox>
#include <QFileDialog>
#include <QtWidgets>
#include <QCompleter>
#include <QSqlQueryModel>

#include "wfwebview.h"
//#include "networkaccessmanager.h"
#include "cookiejar.h"
#include "types.h"
#include "bookmarks.h"
#include "historydatabase.h"

namespace Ui {
    class MainWindow;
}


class WFWebView;
class Bookmarks;

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
    friend class Bookmarks;
    
public slots:
    void quit();
    void options();
    void about();
    
    void sidebarBookmarks();
    
    void gotoURL();
    void gotoURL(QString url);
    void diagnoseLoad(bool ok);
    void changeTab(int index);
    void newTab();
    void newTab(WFWebView* &view);
    void closeTab();
    void closeTab(int index);
    void newPage(QWebFrame* frame);
    void back();
    void forward();
    void reload();
    void stop();
    void loadInteraction();
    void bookmarkAdd();
    void loadBookmark();
    void loadBookmark(QTreeWidgetItem* item, int column);
    void downloadContent(QNetworkReply* reply);
    void downloadContent(QNetworkRequest request);
    void linkHovered(const QString &link, const QString &title, 
                     const QString &textContent);
    
    void gotoAddressBar();
    void startSearch();
    
private slots:
    void addressBarTextChanged(const QString &text);
    void historyItemTriggered(int index);
    void tabTitleChanged(QString title);
    void tabIconChanged();
    void newHistoryTab();
    void openHistoryDialog();
    
protected:
    void closeEvent(QCloseEvent* event);

private:
    void setStopButton();
    void setReloadButton();
    
    Ui::MainWindow* ui;
    QSettings* settings;
    QString storagePath;        // storage location for application data.
    WFWebView* wv;              // current webview instance pointer
    QString icondb;             // path to storage location for site icons.
    QDir savedir;               // directory to save to.
    QNetworkAccessManager* nam; // the central network access manager
    CookieJar* cookiejar;       // reference to the cookiejar in use
    Bookmarks* bookmarks;       // the bookmarks object.
    HistoryDatabase* historydb; // the history database
    QFile manifest;
    QList<QWebPage*> extPages;      // Extension pages
    QList<Filter> extFilters;       // Extension content script filters
    bool stopbutton;                // is the stop page load button visible?
    //QTableWidget* historyTable;   // Address bar pop-up showing the history items.
    QList<HistoryObject> objects;   // Objects being shown in address bar popup.
    QCompleter* completer;          // the address bar completer object.
    QSqlQueryModel* historyModel;   // history db query model.
};

#endif // MAINWINDOW_H


<|start_filename|>iofile.h<|end_filename|>
/*
  iofile.h - IO File definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - This class allows one to directly couple a network download to a
            QFile.
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/

#ifndef IOFILE_H
#define IOFILE_H

#include <QFile>
#include <QtNetwork/QNetworkReply>

class IOFile : public QFile {
    Q_OBJECT
    
    // we add a new function to assign a QNetworkReply instance and a new slot
    // to respond to newly available data.
public:
    void setNetworkReply(QNetworkReply* reply);
    
public slots:
    void readProgress(qint64 current, qint64 total);
    void readFromReply();
    void cancel();
    void terminate();
    
signals:
    void progress(int percentage);
    
private:
    QNetworkReply* reply;
};

#endif // IOFILE_H


<|start_filename|>wfwebview.cpp<|end_filename|>
/*
  mainwindow.cpp - Main implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/

#include "wfwebview.h"
#include <QDebug>

// --- CONSTRUCTOR ---
WFWebView::WFWebView() {
    // set defaults
    uip = 0;
    /*QWidgetList list = QApplication::topLevelWidgets();
    for (int i = 0; i < list.size(); ++i) {
        if (list[i]->isWindow()) {
            uip = qobject_cast<MainWindow*>(list[i]);
            break;
        }
    }*/
    setPage(new WFWebPage); // use our custom page class
    
    uip = (MainWindow*) QApplication::activeWindow();
    if (uip == 0) {
        qDebug() << "Failed to find main window: " << uip;
    }
}


// --- SET TAB MANAGER ---
// Set the tab manager to use with this WFWebView instance.
/*void WFWebView::setTabManager(TabManager* tabman) {
    tabmanager = tabman;
}*/


// --- SET UI PARENT ---
// Sets the object managing the UI objects.
/*void WFWebView::setUIParent(MainWindow* parent) {
    uip = parent;
}*/


// --- CREATE WINDOW ---
QWebView* WFWebView::createWindow(QWebPage::WebWindowType type) {
    if (type == QWebPage::WebBrowserWindow) {
        // ensure we have a pointer to the main window object
        if (uip == 0) {
            // no object set just yet. We return null;
            return 0;
        }
        
        WFWebView* wv = 0;
        uip->newTab(wv);
        qDebug() << "WFWebView wv: " << wv;
        return wv;
    }
    else if (type == QWebPage::WebModalDialog) {
        // TODO: just return a new tab for now.
        WFWebView* wv = 0;
        uip->newTab(wv);
        return wv;
    }
    
    return 0;
}


// --- CONTEXT MENU EVENT ---
// Handle context menu events.


<|start_filename|>chrome/chromejsinterface.cpp<|end_filename|>
/*
  chromejsinterface.cpp - Network access manager implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2012/03/20, <NAME>
  (c) Nyanko.ws
*/


#include "chromejsinterface.h"


// --- CONSTRUCTOR ---
ChromeJSInterface::ChromeJSInterface(MainWindow *window, Bookmarks *bookmarks) {
    mw = window;
    bm = bookmarks;
    
    this->bookmarks = new ChromeBookmarks(bm);
}


// --- DECONSTRUCTOR ---
ChromeJSInterface::~ChromeJSInterface() {
    //
}


<|start_filename|>sessions.h<|end_filename|>
/*
  sessions.h - declaration of WildFox's Sessions class.
  
  Revision 0
        
  Notes:
        - 
        
  2013/04/21, <NAME>
  (c) Nyanko.ws
*/

#ifndef SESSIONS_H
#define SESSIONS_H

#include <QObject>
#include <QSqlDatabase>


struct SessionInfo {
    QString name;
    QString filename;
};


class Sessions : public QObject {
    Q_OBJECT
public:
    explicit Sessions(QObject *parent = 0);
    
    QList<SessionInfo> listSessions();
    int openSession(QString path);
    int saveSession(QString path);
    int newSession(QString path);
    
    int newTab();
    int addTabItem(int position);
    int changeTabPosition(int oldPos, int newPos);
    
signals:
    
public slots:
    
private:
    QSqlDatabase db;
    bool active_db;
};

#endif // SESSIONS_H


<|start_filename|>wfwebpage.h<|end_filename|>
/*
  wfwebpage.h - declaration of WildFox's WFWebPage class.
  
  Revision 0
        
  Notes:
        - 
        
  2013/03/26, <NAME>
  (c) Nyanko.ws
*/


#ifndef WFWEBPAGE_H
#define WFWEBPAGE_H

#include <QWebPage>

class WFWebPage : public QWebPage {
    Q_OBJECT
public:
    explicit WFWebPage(QWidget *parent = 0);
    bool supportsExtension(Extension extension) const;
    bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
    
signals:
    
public slots:
    
};

#endif // WFWEBPAGE_H


<|start_filename|>networkaccessmanager.cpp<|end_filename|>
/*
  networkaccessmanager.cpp - Network access manager implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - Implements URL filter to add content scripts to a page.
        - TODO: add adblocker support?
        
  Notes:
        - 
        
  2012/02/21, <NAME>
  (c) Nyanko.ws
*/

#include "networkaccessmanager.h"

#include <QNetworkReply>
#include <QNetworkRequest>
#include <QStringList>



// --- SET FILTERS ---
// Sets the filters which activate a particular extension's content scripts
void NetworkAccessManager::setFilters(QList<Filter> &filters) {
    this->filters = filters;
}


// --- GET FILTERS ---
// Return the currently set filters.
QList<Filter>* NetworkAccessManager::getFilters() {
    return &filters;
}


// --- CREATE REQUEST ---
// Extends the default function. Does comparison on the current GET URL.
// Injects content script into page if GET request & match is found.
QNetworkReply* NetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
    if (op == QNetworkAccessManager::GetOperation) {
        if (filters.size() < 1) {
            return QNetworkAccessManager::createRequest(op, request);
        }
        
        QNetworkReply* reply = QNetworkAccessManager::createRequest(op, request);
        if (reply->error() == QNetworkReply::NoError) {
            return reply;
        }
        
        QString url = request.url().toString();
        QStringList urlbit;
        urlbit = url.split("://");
        if (urlbit.size() > 1) {
            QString scheme = urlbit[0];
            QStringList bits = urlbit[1].split(".");
            for (int i = 0; i < filters.size(); ++i) {
                if (filters[i].scheme != scheme) { continue; }
                for (int j = 0; filters[i].segments.size(); ++j) {
                    if (filters[i].segments[j] != bits[j] && filters[i].segments[j] != "*") {
                        continue;
                    }
                }
                
                // matched filter, inject associated scripts into the content.
            }
        }
    }
}


<|start_filename|>networkaccessmanager.h<|end_filename|>
/*
  networkaccessmanager.h - network access manager declaration file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2012/02/21, <NAME>
  (c) Nyanko.ws
*/

#ifndef NETWORKACCESSMANAGER_H
#define NETWORKACCESSMANAGER_H

#include <QNetworkAccessManager>
#include "types.h"


class NetworkAccessManager : public QNetworkAccessManager {
    Q_OBJECT
    
public:
    void setFilters(QList<Filter> &filters);
    QList<Filter>* getFilters();
    
protected:
    QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData);
    
private:
    QList<Filter> filters;
};
        

#endif // NETWORKACCESSMANAGER_H


<|start_filename|>addressbarcompleter.cpp<|end_filename|>
/*
  addressbarcompleter.cpp - implementation of the address bar completer class.
  
  Revision 0
  
  Features:
        - Reimplements the QCompleter class to allow more useful filtering.
        
  Notes:
        - 
        
  2013/05/18, <NAME>
  (c) Nyanko.ws
*/


#include "addressbarcompleter.h"


// --- CONSTRUCTOR ---
AddressBarCompleter::AddressBarCompleter(QObject *parent) : QCompleter(parent) {
    //
}


// --- SET COMPLETION PREFIX ---
// Overrides the function in QCompleter. This reimplementation doesn't set the text
// from the line edit (address bar) as the prefix to search for, but 


<|start_filename|>chrome/chromejsinterface.h<|end_filename|>
/*
  chromejsinterface.h - Chrome JS Interface definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - Definition of the Chrome extension support implementation.
        
  2012/03/19, <NAME>
  (c) Nyanko.ws
*/

#ifndef CHROMEJSINTERFACE_H
#define CHROMEJSINTERFACE_H

//#include <QObject>


class MainWindow;
class Bookmarks;
//class ChromeBookmarks;
class ChromeBrowserAction;
class ChromeExtension;
class ChromeI18n;
class ChromeSelf;
class ChromeTabs;
class ChromeWindows;


#include "chromebookmarks.h"


class ChromeJSInterface : public QObject {
    Q_OBJECT
    
public:
    ChromeJSInterface(MainWindow* window, Bookmarks* bookmarks);
    ~ChromeJSInterface();
    
private:
    MainWindow* mw;
    Bookmarks* bm;
    ChromeBookmarks* bookmarks;
    ChromeBrowserAction* browserAction;
    ChromeExtension* extension;
    ChromeI18n* i18n;
    ChromeSelf* self;
    ChromeTabs* tabs;
    ChromeWindows* windows;
};

#endif // CHROMEJSINTERFACE_H


<|start_filename|>tldutil.h<|end_filename|>
/*
  tldutil.h - URL Top Level Domain utility definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2012/02/07, <NAME>
  (c) Nyanko.ws
*/

#ifndef TLDUTIL_H
#define TLDUTIL_H

#include <QtCore>

bool isEffectiveTLD(const QString &domain);
QString getPublicDomain(const QString &domain);
QString topLevelDomain(const QString &domain);

#endif // TLDUTIL_H


<|start_filename|>sessions.cpp<|end_filename|>
/*
  sessions.cpp - implementation of WildFox's Sessions class.
  
  Revision 0
  
  Features:
        - Allows for the selection of a session file.
        - Saving to a session file.
        - Restoring from a session file.
        
  Notes:
        - 
        
  2013/04/21, <NAME>
  (c) Nyanko.ws
*/


#include "sessions.h"

#include <QFileInfo>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>


// --- CONSTRUCTOR ---
Sessions::Sessions(QObject *parent) : QObject(parent) {
    // defaults;
    active_db = false;
}


// --- LIST SESSIONS ---
// Returns a list of available sessions found in the sessions folder.
QList<SessionInfo> Sessions::listSessions() {
    QList<SessionInfo> list;
    
    return list;
}


// --- OPEN SESSION ---
// Opens the session file indicated by parameter 'name', and closes any existing
// session.
int Sessions::openSession(QString path) {
    QFileInfo info(path);
    if (!info.exists()) { return 1; }
    if (active_db) {
        db.close();
        QSqlDatabase::removeDatabase("sessiondb");
    }
    
    db = QSqlDatabase::addDatabase("QSQLITE", "sessiondb");
    db.setDatabaseName(path);
    if (!db.open()) {
        qDebug() << "Failed to open the session database " << path;
        qDebug() << "Cause: " << db.lastError().text();
        return 1;
    }
    
    active_db = true;
    QSqlQuery query(db);
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='tabs'");
    if (!query.next()) {
        // table doesn't exist, create it.
        bool err = query.exec("CREATE TABLE tabs (id INTEGER, PRIMARY KEY, position INTEGER, lastModified INTEGER)");
        if (!err) {
            qDebug() << "Creating tabs table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
        
        err = query.exec("CREATE INDEX tabs_position ON tabs (position)");
        if (!err) {
            qDebug() << "Creating tabs_position index on tabs table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
        
        err = query.exec("CREATE INDEX tabs_lastmodified ON tabs (lastModified)");
        if (!err) {
            qDebug() << "Creating tabs_lastmodified index on tabs table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
    }
    
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='items'");
    if (!query.next()) {
        // table doesn't exist, create it.
        bool err = query.exec(QString("CREATE TABLE items (id INTEGER PRIMARY KEY, tabs_id INTEGER, ") +
                              QString("url TEXT,title TEXT, lastModified INTEGER)"));
        if (!err) {
            qDebug() << "Creating items table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
        
        err = query.exec("CREATE INDEX items_tabs_id ON items (tabs_id)");
        if (!err) {
            qDebug() << "Creating items_tabs_id index on items table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
    }
    
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='visits'");
    if (!query.next()) {
        // table doesn't exist, create it.
        bool err = query.exec(QString("CREATE TABLE visits (id INTEGER PRIMARY KEY, tabs_id INTEGER,") +
                              QString("items_id INTEGER, timestamp INTEGER)"));
        if (!err) {
            qDebug() << "Creating visits table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
        
        err = query.exec("CREATE INDEX visits_tabs_id ON visits (tabs_id)");
        if (!err) {
            qDebug() << "Creating visits_tabs_id index on visits table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
        
        err = query.exec("CREATE INDEX visits_timestamp ON visits (timestamp)");
        if (!err) {
            qDebug() << "Creating visits_timestamp index on visits table failed.";
            qDebug() << "Cause: " << db.lastError().text();
            return 1;
        }
    }
    
    return 0;
}


// --- SAVE SESSION ---
// Save the current session to the provided path and switch to using that session
// file.
int Sessions::saveSession(QString path) {
    //
    
    return 0;
}


// --- NEW SESSION ---
// Create a new, empty session file at the provided path and switch to using that
// file.
int Sessions::newSession(QString path) {
    //
    
    return 0;
}


// --- NEW TAB ---
// Creates a new tab entry in the session file.
int Sessions::newTab() {
    //
    
    return 0;
}


// -- ADD TAB ITEM ---
// Inserts a new history item for the specified tab.
int Sessions::addTabItem(int position) {
    //
    
    return 0;
}


// --- CHANGE TAB POSITION ---
// Changes the tab indicated by oldPos parameter to position newPos. Tabs with a position
// equal to or higher than newPos have their position increased by one, up to the gap
// left by oldPos, if oldPos is higher than newPos.
int Sessions::changeTabPosition(int oldPos, int newPos) {
    //
    
    return 0;
}


<|start_filename|>addressbareventfilter.cpp<|end_filename|>
/*
  addressbareventfilter.cpp - addressBarEventFilter class implementation file of WildFox.

  Revision 0

  Features:
        - Implements an event filter for the QComboBox class.
        - Emits a signal when the combobox's popup is activated.

  Notes:
        -

  2013/04/25, <NAME>
  (c) Nyanko.ws
*/


#include "addressbareventfilter.h"


// --- CONSTRUCTOR ---
addressBarEventFilter::addressBarEventFilter(QObject *parent) :
    QObject(parent) {
    //
}


// --- EVENT FILTER ---
// Reimplements virtual function to emit a signal when the popup is opened.
bool addressBarEventFilter::eventFilter(QObject *, QEvent *) {
    //
    
    return true;
}


<|start_filename|>chrome/chromebookmarks.h<|end_filename|>
/*
  chromebookmarks.h - bookmarks definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - Definition of the bookmarks functions class.
        
  2012/03/20, <NAME>
  (c) Nyanko.ws
*/


#ifndef CHROMEBOOKMARKS_H
#define CHROMEBOOKMARKS_H


#include <QtWebKit>

//class Bookmarks;
#include "../bookmarks.h"


class ChromeBookmarks : public QObject {
    Q_OBJECT
    
public:    
    ChromeBookmarks(Bookmarks* bookmarks);
    ~ChromeBookmarks();
    
    Q_INVOKABLE QVariantMap create(QVariantMap bookmark, QString callback);
    
private:
    Bookmarks* bm;
};

#endif // CHROMEBOOKMARKS_H


<|start_filename|>cookiemanagedialog.cpp<|end_filename|>
/*
  cookiemanagedialog.cpp - Cookie Manage dialog implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - Allows checking of cookie details and deleting cookies.
        
  Notes:
        - 
        
  2012/02/09, <NAME>
  (c) Nyanko.ws
*/


#include "cookiemanagedialog.h"
#include "ui_cookiemanagedialog.h"
#include "tldutil.h"

#include <QSqlQuery>
#include <QMessageBox>
#include <QDebug>
#include <QSqlError>


#define FOLDER 1000
#define COOKIE 2000


// --- CONSTRUCTOR ---
CookieManageDialog::CookieManageDialog(QSqlDatabase* db, QMultiMap<QString, QNetworkCookie> *buffer, QWidget *parent) : QDialog(parent),
    ui(new Ui::CookieManageDialog) {
    ui->setupUi(this);
    
    // defaults
    ui->cmLabelName->clear();
    ui->cmLabelValue->clear();
    ui->cmLabelDomain->clear();
    ui->cmLabelSendFor->clear();
    ui->cmLabelPath->clear();
    ui->cmLabelExpires->clear();
    
    // read info from database
    this->db = db;
    this->cookiebuffer = buffer;
    
    QSqlQuery query(*this->db);
    query.exec("SELECT baseDomain, name, value, host, path, expiry, isSecure, isHttpOnly FROM moz_cookies ORDER BY baseDomain");
    if (!query.isActive()) {
        qDebug() << "Failed to fetch cookies from DB: " << query.lastError().text();
        return;
    }
    else if (query.next()){
        // extract data and assemble into a Tree
        CookieData cd;
        baseDomain = "";
        //QList<QTreeWidgetItem*> items;
        QTreeWidgetItem* parent = 0;
        QTreeWidgetItem* item = 0;
        int cIndex = 0; // current index into cookiedata list
        do {
            // Check whether this top domain folder exists, create if not.
            if (query.value(0) != baseDomain) {
                baseDomain = query.value(0).toString();
                parent = new QTreeWidgetItem((QTreeWidget*) 0, QStringList(baseDomain), FOLDER);
                //items.append(parent);
                ui->cmTree->addTopLevelItem(parent);
            }
            
            QStringList list;
            list << query.value(3).toString() << query.value(1).toString();
            item = new QTreeWidgetItem(parent, list, COOKIE);
            item->setData(0, Qt::UserRole, QVariant(cIndex));
            parent->addChild(item);
            cd.expiry.setTime_t((uint) query.value(5).toULongLong());
            cd.name = query.value(1).toString();
            cd.value = query.value(2).toString();
            cd.host = query.value(3).toString();
            cd.path = query.value(4).toString();
            //cd.expiry = query.value(5);
            cd.isSecure = query.value(6).toBool();
            cd.isHttpOnly = query.value(7).toBool();
            
            // insert into list and increase index count
            cookiedata.append(cd);
            ++cIndex;
        } while (query.next());
    }
    
    // set up connections
    connect(ui->cmTree, SIGNAL(itemSelectionChanged()), this, SLOT(showCookieDetails()));
    connect(ui->cmButtonDelete, SIGNAL(pressed()), this, SLOT(deleteCookie()));
    connect(ui->cmButtonDeleteAll, SIGNAL(pressed()), this, SLOT(deleteAllCookies()));
    connect(ui->cmButtonClose, SIGNAL(pressed()), this, SLOT(close()));
}

// --- DECONSTRUCTOR ---
CookieManageDialog::~CookieManageDialog() {
    delete ui;
}


// --- SHOW COOKIE DETAILS ---
// Show the details of the currently selected cookie. We pick the first item
// in the list of selected items.
void CookieManageDialog::showCookieDetails() {
    QList<QTreeWidgetItem*> items = ui->cmTree->selectedItems();
    CookieData cd = cookiedata[items[0]->data(0, Qt::UserRole).toInt()];
    ui->cmLabelName->setText(cd.name);
    ui->cmLabelValue->setText(cd.value);
    ui->cmLabelDomain->setText(cd.host);
    ui->cmLabelPath->setText(cd.path);
    ui->cmLabelSendFor->setText(QString(cd.isHttpOnly?"HTTP":"HTTP/HTTPS"));
    ui->cmLabelExpires->setText(cd.expiry.toString(Qt::ISODate));
}


// --- DELETE COOKIE ---
// Delete the currently selected cookie(s). Just remove the tree children.
// FIXME: remove the parent if all children are deleted?
void CookieManageDialog::deleteCookie() {
    QList<QTreeWidgetItem*> items = ui->cmTree->selectedItems();
    for (int i = 0; i < items.size(); ++i) {
        if (items[i]->type() == COOKIE) {
            int cookieID = items[i]->data(0, Qt::UserRole).toInt();
            QTreeWidgetItem* parent = items[i]->parent();
            //int index = parent->indexOfChild(items[i]);
            parent->removeChild(items[i]);
            
            // remove the items from the database and cookiebuffer
            CookieData cookie = cookiedata[cookieID];
            baseDomain = getPublicDomain(cookie.host);
            QMap<QString, QNetworkCookie>::iterator cit;
            cit = cookiebuffer->find(baseDomain);
            if (cit != cookiebuffer->end()) {
                // delete in the buffer
                while (cit != cookiebuffer->end() && cit.key() == baseDomain) {
                    QNetworkCookie c = cit.value();
                    if (c.name() == cookie.name &&
                            c.domain() == cookie.host &&
                            c.path() == cookie.path) {
                        // same cookie, delete it
                        cookiebuffer->remove(cit.key(), cit.value());
                    }
                }
                
                cit++;
            }
            
            // delete in the database
            QSqlQuery query(*db);
            query.prepare("DELETE FROM moz_cookies WHERE baseDomain=:baseDomain AND path=:path AND name=:name ");
            query.bindValue(":baseDomain", baseDomain);
            query.bindValue(":path", cookie.path);
            query.bindValue(":name", cookie.name);
            bool err = query.exec();
            if (!err) {
                qDebug() << "Failed to update database with query: " << query.lastQuery();
                continue;
            }
        }
    }
}


// --- DELETE ALL COOKIES ---
// Delete all cookies. Ask for confirmation.
void CookieManageDialog::deleteAllCookies() {
    int response = QMessageBox::question(this, tr("Delete Cookies"), tr("Do you want to delete all stored cookies?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
    if (response == QMessageBox::Yes) {
        cookiebuffer->clear();
    }
    
    // delete in the database
    QSqlQuery query;
    query.exec("DELETE FROM moz_cookies");
    if (!query.isActive()) {
        qDebug() << "Failed to update database with query: " << query.lastQuery();
    }
}


// --- CLOSE ---
// Closes the dialogue.
void CookieManageDialog::close() {
    done(1);
}


<|start_filename|>bookmarks.cpp<|end_filename|>
/*
  bookmarks.cpp - Network access manager implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2012/02/21, <NAME>
  (c) Nyanko.ws
*/


#include "bookmarks.h"

#include <QSqlQuery>
#include <QAction>
#include <QTreeWidgetItem>
#include <QDesktopServices>
#include <QDateTime>


// --- CONSTRUCTOR ---
Bookmarks::Bookmarks(MainWindow *window) {
    mw = window;
    
    // open the bookmarks database file if present. Check its integrity. Create
    // a default instance if there are any issues.
    storagePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
    storagePath = QDir::toNativeSeparators(storagePath + "/");
    db = QSqlDatabase::addDatabase("QSQLITE", "bookmarksdb");
    db.setDatabaseName(storagePath + "bookmarks.sqlite");
    if (!db.open()) {
        qDebug("Failed to open the bookmarks database.");
        qDebug() << "Cause: " << db.lastError().text();
        return;
    }
    
    QSqlQuery query(db);
    query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='bookmarks'");
    if (!query.next()) {
        // table doesn't exist, create it.
        query.finish();
        bool err = query.exec(QString("CREATE TABLE bookmarks (id INTEGER PRIMARY KEY, ") +
                   QString("type INTEGER, fk INTEGER DEFAULT NULL, parent INTEGER, ") +
                   QString("position INTEGER, title TEXT, url TEXT, keyword_id INTEGER, ") + 
                   QString("folder_type TEXT, dateAdded INTEGER, lastModified INTEGER, guid TEXT)"));
        if (!err) {
            qDebug("Creating bookmarks table failed.");
            qDebug() << "Cause: " << db.lastError().text();
            return;
        }        
        
        // add default content
        query.finish();
        err = query.exec("INSERT INTO bookmarks (id, type, parent, position, title, url, " +
                QString("keyword_id, folder_type, dateAdded, lastModified, guid)") +
                QString(" VALUES (1, 1, 0, 0, '', '', 0, '', 0, 0, 'dRm4PcMt67gO')"));
        if (!err) {
            qDebug() << "Failed to insert default bookmark data.";
            qDebug() << "Cause: " << query.lastError().text();
            return; 
        }
    }
    
    query.finish();
    contextmenu = new QMenu(mw->ui->bookmarksTree);
    mw->ui->bookmarksTree->setContextMenuPolicy(Qt::ActionsContextMenu);
    QAction* deleteAction = new QAction(tr("Delete Bookmark"), contextmenu);
    mw->ui->bookmarksTree->addAction(deleteAction);
    connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteBookmark()));
    createBookmarksMenu();
}


// --- DECONSTRUCTOR ---
Bookmarks::~Bookmarks() {
    db.close();
}


// --- CREATE BOOKMARKS MENU ---
// Assemble the bookmarks menu from scratch.
void Bookmarks::createBookmarksMenu() {
    mw->ui->menuBookmarks->clear();
    mw->ui->bookmarksTree->clear();
    menus.clear();
    actions.clear();
    QAction* actionAdd = mw->ui->menuBookmarks->addAction("Bookmark this page");
    actionAdd->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
    connect(actionAdd, SIGNAL(triggered()), mw, SLOT(bookmarkAdd()));
    mw->ui->menuBookmarks->addSeparator();
    
    // Assemble the in-memory bookmark data structures
    // FIXME: just retrieving in a 'flat' style now, not dealing with folders.
    //          Fetching only bookmarks and basic info now.
    QSqlQuery query(db);
    bool err = query.exec("SELECT id, type, parent, title, url FROM bookmarks");
    if (!err) {
        qDebug() << "Failed to fetch bookmarks from database.";
        qDebug() << "Cause: " << query.lastError().text();
        return;
    }
    
    while (query.next()) {
        int type = query.value(1).toInt();
        int parent = query.value(2).toInt();
        qDebug() << "Type: " << type << ", parent: " << parent;
        MenuItem item;
        ActionItem action;
        if (type == TYPE_FOLDER) {
            item.id = query.value(0).toInt();
            item.item = new QMenu(query.value(3).toString());
            menus.insert(parent, item);
        }
        else if (type == TYPE_BOOKMARK) {
            action.id = query.value(0).toInt();
            action.action = new QAction(query.value(3).toString(), mw);
            action.action->setData(query.value(4).toString());
            action.action->setIcon(QIcon(QWebSettings::iconForUrl(QUrl(query.value(4).toString()))));
            connect(action.action, SIGNAL(triggered()), mw, SLOT(loadBookmark()));
            actions.insert(parent, action);
        }
    }
    
    // Set the bookmarks actions/menus in the GUI.
    // First fetch the root folder (ID:1), call the recursive function on it.
    if (menus.contains(1) || actions.contains(1)) {
        QTreeWidgetItem* treeitem = new QTreeWidgetItem(mw->ui->bookmarksTree);
        treeitem->setText(0, "Bookmarks");
        //qDebug() << "Adding items to root.";
        recursiveTreeDescent(mw->ui->menuBookmarks, treeitem, 1);
        mw->ui->bookmarksTree->expandAll();
    }
    else {
        qDebug() << "No root folder found for bookmarks.";
    }
}


// --- RECURSIVE TREE DESCENT ---
// Constructs a single menu folder, calls itself recursively to construct sub-folders.
void Bookmarks::recursiveTreeDescent(QMenu* menu, QTreeWidgetItem *parentfolder, int parentID) {
    QList<MenuItem> folders = menus.values(parentID);
    QTreeWidgetItem* item;
    for (int i = 0; i < folders.size(); ++i) {
        //qDebug() << "Found folder, adding...";
        item = new QTreeWidgetItem(parentfolder);
        item->setText(0, folders[i].item->title());
        //qDebug() << "Name: " << item->text(0);
        recursiveTreeDescent(folders[i].item, item, folders[i].id);
        menu->addMenu(folders[i].item);
    }
    
    QList<ActionItem> bookmarks = actions.values(parentID);
    //menu->addActions(bookmarks);
    QList<QVariant> bookmarkdata;
    for (int i = 0; i < bookmarks.size(); ++i) {
        menu->addAction(bookmarks[i].action);
        bookmarkdata.clear();
        //qDebug() << "Found bookmark, adding...";
        item = new QTreeWidgetItem(parentfolder);
        item->setText(0, bookmarks[i].action->text());
        item->setIcon(0, QIcon(QWebSettings::iconForUrl(QUrl(bookmarks[i].action->data().toString()))));
        //qDebug() << "Name: " << item->text(0);
        bookmarkdata.append(bookmarks[i].action->data());   // ID 0
        bookmarkdata.append(bookmarks[i].id);               // ID 1
        item->setData(0, Qt::UserRole, bookmarkdata);
    }
}


// --- CREATE ---
// Create the new bookmark, regenerate the bookmarks menu and return the node map.
// Return immediately if no URL is present in the bookmark data.
QVariantMap Bookmarks::create(QVariantMap bookmark) {
    if (!bookmark.contains("url")) { return bookmark; }
    //QVariantMap node;
    QSqlQuery query(db);
    QDateTime time;
    query.prepare("INSERT INTO bookmarks (type, parent, position, title, url, " +
                  QString("keyword_id, folder_type, dateAdded, lastModified, guid) ") +
                  QString("VALUES (:type, :parent, :position, :title, :url, :kid,") +
                  QString(":ft, :added, :modified, :guid)"));
    query.bindValue(":type", TYPE_BOOKMARK);
    query.bindValue(":parent", 1); // attach to root
    query.bindValue(":position", 0); // unsorted
    query.bindValue(":title", bookmark.value("title", "Untitled").toString());
    query.bindValue(":url", bookmark.value("url", "").toString());
    query.bindValue(":kid", 0);
    query.bindValue(":ft", 0);
    query.bindValue(":added", time.toTime_t());
    query.bindValue(":modified", time.toTime_t());
    query.bindValue(":guid", ""); // TODO: generate GUID
    bool err = query.exec();
    if (!err) {
        qDebug() << "Failed to update database with query: " << query.executedQuery();
        qDebug() << "Cause: " << query.lastError().text();
        return bookmark;
    }
    
    emit bookmarkCreated();
    createBookmarksMenu();
    
    return bookmark;
}


// --- DELETE BOOKMARK ---
// Delete the currently selected bookmark.
void Bookmarks::deleteBookmark() {
    qDebug() << "Delete triggered.";
    QTreeWidgetItem* item = mw->ui->bookmarksTree->currentItem();
    int id = item->data(0, Qt::UserRole).toList()[1].toInt();
    QSqlQuery query(db);
    query.prepare("DELETE FROM bookmarks WHERE id=:id");
    query.bindValue(":id", id);
    bool err = query.exec();
    if (!err) {
        qDebug() << "Failed to delete bookmark from database with query: " << query.executedQuery();
        qDebug() << "Cause: " << query.lastError().text();
    }
    
    createBookmarksMenu(); // re-create the menu
}


<|start_filename|>tabhistory.cpp<|end_filename|>
/*
  tabhistory.cpp - implementation of WildFox's TabHistory class.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2013/06/01, <NAME>
  (c) Nyanko.ws
*/


#include "tabhistory.h"


// --- CONSTRUCTOR ---
TabHistory::TabHistory(QObject *parent) : QObject(parent) {
    //
}


// --- CLEAR ---
// Clear the list of history items.
void TabHistory::clear() {
    historyItems.clear();
}


// --- ITEMS ---
// Return the list of history items.
QList<TabHistoryItem> TabHistory::items() const {
    return historyItems;
}


// --- BACK ITEMS ---
// Return the maxItems last history items from current item towards the back of
// the history items list.
QList<TabHistoryItem> TabHistory::backItems(int maxItems) const {
    QList<TabHistoryItem> list;
    
    return list;
}


// --- FORWARD ITEMS ---
// Return the first maxItems history items from current item towards the front of
// the history items list.
QList<TabHistoryItem> TabHistory::forwardItems(int maxItems) const {
    QList<TabHistoryItem> list;
    return list;
}


// --- CAN GO BACK ---
// Whether there's an item behind the current history item.
bool TabHistory::canGoBack() const {
    //
    
    return false;
}


// --- CAN GO FORWARD ---
// Whether there's an item before the current history item.
bool TabHistory::canGoForward() const {
    //
    
    return false;
}


// --- BACK ---


<|start_filename|>mainwindow.cpp<|end_filename|>
/*
  mainwindow.cpp - Main implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - Uses the JSON parser from http://ereilin.tumblr.com/post/6857765046/lightweight-json-parser-serializer-class-for-qt
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/

#include "mainwindow.h"

#include <QtGui>
#include <QWebView>
#include <QtUiTools/QUiLoader>
#include <QDesktopServices>
#include <QNetworkProxyFactory>
#include <QWebFrame>
#include <QWebElement>
#include <QList>
#include <QWebHistory>

#include "iofile.h"
#include "optionsdialog.h"
#include "json.h"
#include "wfwebhistoryinterface.h"
#include "addressbardelegate.h"
#include "addressbareventfilter.h"
#include "historydialog.h"


// --- CONSTRUCTOR ---
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    
    //qDebug() << "Mew?";
    
    // menu connections
    connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(quit()));
    connect(ui->actionAbout_WildFox, SIGNAL(triggered()), this, SLOT(about()));
    connect(ui->actionNewTab, SIGNAL(triggered()), this, SLOT(newTab()));
    connect(ui->actionClose_Tab, SIGNAL(triggered()), this, SLOT(closeTab()));
    connect(ui->actionOptions, SIGNAL(triggered()), this, SLOT(options()));
    connect(ui->actionBookmarksSidebar, SIGNAL(triggered()), this, SLOT(sidebarBookmarks()));
    
    // other interface connections
    connect(ui->backButton, SIGNAL(pressed()), this, SLOT(back()));
    connect(ui->forwardButton, SIGNAL(pressed()), this, SLOT(forward()));
    connect(ui->reloadButton, SIGNAL(pressed()), this, SLOT(loadInteraction()));
    //ui->tabWidget->addAction(ui->actionReload);
    connect(ui->actionReload, SIGNAL(triggered()), this, SLOT(reload()));
    connect(ui->actionStop, SIGNAL(triggered()), this, SLOT(stop()));
    connect(ui->addressBar->lineEdit(), SIGNAL(returnPressed()), this, SLOT(gotoURL()));
    //connect(addressBarGo, SIGNAL(pressed()), this, SLOT(gotoURL()));
    connect(ui->historyButton, SIGNAL(pressed()), 
            this, SLOT(openHistoryDialog()));
    connect(ui->searchBar, SIGNAL(returnPressed()), 
            this, SLOT(startSearch()));
    connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, 
            SLOT(changeTab(int)));
    ui->tabWidget->addAction(ui->actionClose_Tab);
    connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
    connect(ui->bookmarksTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)), 
            this, SLOT(loadBookmark(QTreeWidgetItem*,int)));
    
    connect(ui->actionBookmark_this_page, SIGNAL(triggered()), this, SLOT(bookmarkAdd()));
    
    addAction(ui->actionOpen_History_Tab);
    connect(ui->actionOpen_History_Tab, SIGNAL(triggered()), 
            this, SLOT(newHistoryTab()));
    addAction(ui->actionHistory_dialog);
    connect(ui->actionHistory_dialog, SIGNAL(triggered()), 
            this, SLOT(openHistoryDialog()));
            
    addAction(ui->actionGo_to_address_bar);
    connect(ui->actionGo_to_address_bar, SIGNAL(triggered()), this, SLOT(gotoAddressBar()));
    //connect(ui->addressBar->lineEdit(), SIGNAL(textEdited(QString)),
            //this, SLOT(addressBarTextChanged(QString)));
    //connect(ui->addressBar, SIGNAL(activated(int)), this, SLOT(historyItemTriggered(int)));
    
    // defaults
    QCoreApplication::setOrganizationName("Nyanko");
    QCoreApplication::setOrganizationDomain("nyanko.ws");
    QCoreApplication::setApplicationName("WildFox");
    QCoreApplication::setApplicationVersion("0.1 Alpha");
    QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
    QNetworkProxy::setApplicationProxy(proxies[0]);
    wv = 0;
    //icondb = "./";
    historydb = HistoryDatabase::getInstance();
    ui->addressBar->setMaxVisibleItems(10);
    completer = new QCompleter(this);
    historyModel = new QSqlQueryModel;
    historyModel->setQuery("SELECT url FROM history", historydb->db);
    completer->setModel(historyModel);
    completer->setCaseSensitivity(Qt::CaseInsensitive);
    //completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
    ui->addressBar->lineEdit()->setCompleter(completer);
    cookiejar = new CookieJar();
    bookmarks = new Bookmarks(this);
    nam = new QNetworkAccessManager(this);
    nam->setCookieJar(cookiejar);
    WFWebHistoryInterface::setDefaultInterface(new WFWebHistoryInterface);
    stopbutton = false;
    QApplication::setActiveWindow(this);
    //settings = new QSettings("Nyanko", "WildFox");
    settings = new QSettings();
    storagePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
    QDir dir(storagePath);
    if (!dir.exists()) {
        dir.mkpath(storagePath); // create path if it doesn't exist yet
    }
    
    qDebug() << "Storage path: " << storagePath;
    QWebSettings* ws = QWebSettings::globalSettings();
    ws->setAttribute(QWebSettings::PluginsEnabled, true);
    ws->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
    ws->setIconDatabasePath(storagePath);
    
    // load any extensions. For each found extension, read in the JSON manifest
    // and create a WebPage object for background scripts and load the extension
    // into it. Register URL filters.
    // TESTING: XMarks extension is at ./extensions/xmarks/manifest.json
    manifest.setFileName(QString("extensions/xmarks/manifest.json"));
    if (!manifest.exists() || !manifest.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open the manifest file.";
    }
    else {
        QString manifestString = manifest.readAll();
        bool ok;
        QMap<QString, QVariant> result;
        result = QtJson::Json::parse(manifestString, ok).toMap();
        if (!ok) {
            qDebug() << "Parsing of manifest failed.";
        }
        
        if (result.contains("background_page")) {
            // load this extension into a webpage object.
            QWebPage* page = new QWebPage;
            page->mainFrame()->load(manifest.fileName());
            extPages.append(page);
        }
        
        if (result.contains("content_scripts")) {
            // add the content scripts in this list to the specified filters.
            QMap<QString, QVariant> scripts = result["content_scripts"].toMap();
            if (scripts.contains("matches")) {
                QList<QVariant> matches = scripts["matches"].toList();
                QList<QVariant> js = scripts["js"].toList();
                Filter filter;
                filter.extId = extPages.size() - 1;
                for (int i = 0; i < js.size(); ++i) {
                    filter.scripts.append(QString("extensions/xmarks/") + js[i].toString());
                }
                
                for (int i = 0; i < matches.size(); ++i) {
                    QStringList urlbit = matches[i].toString().split("://");
                    if (urlbit.size() < 2) { continue; }
                    filter.scheme = urlbit[0];
                    filter.segments = urlbit[1].split(".");
                    if (filter.scripts.size() < 1 || filter.segments.size() < 1) {
                        break; // empty/useless filter, skip
                    }
                    
                    extFilters.append(filter);
                }
            }
        }
    }
    
    // Restore application state
    restoreGeometry(settings->value("geometry").toByteArray());
    restoreState(settings->value("windowState").toByteArray());
    ui->bookmarksTree->setVisible(settings->value("bookmarkSidebar", false).toBool());
    
    // pass extension filter data to the network access manager
    //nam->setFilters(extFilters);
    
    // change the address bar QComboBox to use a QTableView instead of its default
    // QListView.
    /*historyTable = new QTableWidget();
    ui->addressBar->setModel(historyTable->model());
    ui->addressBar->setView(historyTable);
    historyTable->setRowCount(10);
    historyTable->setColumnCount(2);
    connect(historyTable, SIGNAL(itemActivated(QTableWidgetItem*)),
            this, SLOT(historyItemTriggered(QTableWidgetItem*)));*/
    
    // Add the custom delegate to the address bar.
    AddressBarDelegate* delegate = new AddressBarDelegate;
    ui->addressBar->setItemDelegate(delegate);
    
    // open empty tab
    newTab();
}


// --- DECONSTRUCTOR ---
MainWindow::~MainWindow() {
    //delete nam;
    delete settings;
    //delete historydb;
    delete ui;
}


// --- SET STOP BUTTON ---
// Changes the UI elements to show a stop loading button with associated shortcut.
void MainWindow::setStopButton() {
    //reloadButton->setText(tr("Stop"));
    ui->reloadButton->setIcon(QIcon(":/wildfox/img/process-stop.png"));
    stopbutton = true;
}


// --- SET RELOAD BUTTON ---
// Changes the UI elements to show a reload page button with associated shorcut.
void MainWindow::setReloadButton() {
    //reloadButton->setText(tr("Reload"));
    ui->reloadButton->setIcon(QIcon(":/wildfox/img/view-refresh.png"));
    stopbutton = false;
}


// --- QUIT ---
void MainWindow::quit() {
    exit(0);
}


// --- OPTIONS ---
// Start the options dialogue.
void MainWindow::options() {
    OptionsDialog dialog(cookiejar);
    dialog.exec();
}


// --- ABOUT ---
void MainWindow::about() {
    QMessageBox::about(this, tr("About WildFox"), tr("WildFox 0.1 by <NAME>\n\nwww.mayaposch.com"));
}


// --- SIDE BAR BOOKMARKS ---
// Hides/shows the bookmarks sidebar.
void MainWindow::sidebarBookmarks() {
    //qDebug() << "Setting sidebar visibility...";
    ui->bookmarksTree->setVisible(!ui->bookmarksTree->isVisible());
    settings->setValue("bookmarkSidebar", !ui->bookmarksTree->isVisible());
    /*if (ui->bookmarksTree->isVisible()) { 
        ui->bookmarksTree->hide(); 
        settings->setValue("bookmarkSidebar", false);
    }
    else { ui->bookmarksTree->setVisible(true); }*/
}


// --- GO TO URL ---
// Go to the URL in the addressbar in the currently open tab. If no tab is open,
// open a new tab.
void MainWindow::gotoURL() {
    QString url = ui->addressBar->lineEdit()->text();
    gotoURL(url);
}


// --- GO TO URL ---
// Go to the url provided in the string.
void MainWindow::gotoURL(QString url) {
    if (ui->tabWidget->count() < 1) { 
        newTab(); // open new tab before proceding
    }
    
    /*QWidget* tab = tabWidget->currentWidget();
    if (!tab) { qDebug("tab is null"); return; }
    
    wv = tab->findChild<WFWebView*>("webView");*/
    wv = (WFWebView*) ui->tabWidget->currentWidget();
    if (!wv) { qDebug("wv is null"); return; }
    
    url.toLower();
    qDebug() << "Lower-case URL: " << url;
    
    // TODO: perform more advanced URL validation.
    if (url.size() < 1) {
        QMessageBox::critical(this, "Error", "No URL provided: " + url);
        return;
    }
    
    if (!url.startsWith("http://") && !url.startsWith("https://")) {
        url.prepend("http://");
        ui->addressBar->lineEdit()->setText(url);
    }
    
    // Load the URL, change the UI elements to allow stopping this action.
    setStopButton();
    wv->load(QUrl(url));
}


// --- DIAGNOSE LOAD ---
// Verify that the page loaded successfully, else present error message.
// If successful, set other data parts and handle filters.
void MainWindow::diagnoseLoad(bool ok) {
    setReloadButton();
    if (!ok) {
        //QMessageBox::critical(this, tr("Error"), tr("Failed to load the URL")); // FIXME: triggers crash with favicon path customized due to QtWebkit bug! 
																					// Don't return to the event loop.
    }
    else {
        // obtain the sender which should be a QWebFrame pointer
        QWebFrame* sender = (QWebFrame*) QObject::sender();
        qDebug() << "Sender: " << sender;
        
        //QWidget* tab = tabWidget->currentWidget
        ui->tabWidget->setTabText(ui->tabWidget->currentIndex(), wv->title());
        ui->tabWidget->setTabIcon(ui->tabWidget->currentIndex(), wv->icon());
        ui->addressBar->lineEdit()->setText(wv->url().toString());
        QString title = wv->title();
        if (title.size() > 200) {
            title.resize(200);
        }
        
        setWindowTitle(title + " - WildFox");
        
        if (wv != 0) {
            ui->backButton->setEnabled(wv->history()->canGoBack());
            ui->forwardButton->setEnabled(wv->history()->canGoForward());
        }
        
        // save page to history database        
        if (sender != 0) {         
            qDebug() << "Adding URL, meow~";
            historydb->addHistoryEntry(sender->url().toString(), sender->title());
        }
        
        // check the page URL against the filters
        if (extFilters.size() < 1) { return; }
        
        QWebPage* page = (QWebPage*) QObject::sender();
        if (page == 0) { return; }        
        QWebFrame* frame = page->mainFrame();
        if (frame == 0) { return; }
        QString url = frame->url().path();
        QStringList urlbit = url.split("://");
        QDir extension;
        extension.setPath(manifest.fileName());
        if (urlbit.size() > 1) {
            QString scheme = urlbit[0];
            QStringList bits = urlbit[1].split(".");
            for (int i = 0; i < extFilters.size(); ++i) {
                if (extFilters[i].scheme != scheme) { continue; }
                for (int j = 0; extFilters[i].segments.size(); ++j) {
                    if (extFilters[i].segments[j] != bits[j] && extFilters[i].segments[j] != "*") {
                        continue;
                    }
                }
                
                // matched filter, inject associated scripts into the content.
                QWebElement root = frame->documentElement();
                QWebElement head = root.findFirst("head");
                head.appendOutside("<script type=\"text/javascript\" src=\"" +
                                   extension.absolutePath() + "\" />");
            }
        }
    }
}


// --- CHANGE TAB ---
// Perform necessary changes here when the active tab has been changed.
void MainWindow::changeTab(int index) {
    if (index == -1) {  // no tabs in tab widget
        setWindowTitle("WildFox");
        wv = 0;
        return; 
    }
    
    wv = (WFWebView*) ui->tabWidget->currentWidget();
    if (!wv) { return; }
    ui->addressBar->lineEdit()->setText(wv->url().toString());
    setWindowTitle(wv->title());
    ui->backButton->setEnabled(wv->history()->canGoBack());
    ui->forwardButton->setEnabled(wv->history()->canGoForward());
}


// --- NEW TAB ---
// Open a new browser tab at the end of the tab bar.
void MainWindow::newTab() {
    qDebug("Loading new tab...");
    //QMessageBox msgBox;
    wv = new WFWebView();
    //connect(wv, SIGNAL(loadFinished(bool)), this, SLOT(diagnoseLoad(bool)));
    connect(wv->page()->mainFrame(), SIGNAL(loadFinished(bool)), 
            this, SLOT(diagnoseLoad(bool)));
    connect(wv, SIGNAL(titleChanged(QString)), 
            this, SLOT(tabTitleChanged(QString)));
    if (wv == 0) {
        qDebug("WV is null");
        return;
    }
    
    wv->page()->setNetworkAccessManager(nam);
    /*QWebSettings* ws = wv->settings();
    ws->setAttribute(QWebSettings::PluginsEnabled, true);
    ws->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
    ws->setIconDatabasePath(icondb);*/
    wv->page()->setForwardUnsupportedContent(true); // enable downloads
    connect(wv->page(), SIGNAL(unsupportedContent(QNetworkReply*)), 
            this, SLOT(downloadContent(QNetworkReply*))); // set up slot
    connect(wv->page(), SIGNAL(downloadRequested(QNetworkRequest)), 
            this, SLOT(downloadContent(QNetworkRequest))); // context menu call
    connect(wv->page(), SIGNAL(linkHovered(QString,QString,QString)), 
            this, SLOT(linkHovered(QString,QString,QString)));
    connect(wv, SIGNAL(iconChanged()), this, SLOT(tabIconChanged()));
    connect(wv, SIGNAL(titleChanged(QString)), this, SLOT(tabTitleChanged(QString)));
    
    //wv->addAction(ui->actionReload);
    qDebug("Settings changed.");
    int index = ui->tabWidget->count();
    ++index;
    index = ui->tabWidget->insertTab(index, wv, tr("New Tab"));
    qDebug("Inserted tab.");
    ui->addressBar->lineEdit()->setText("");
    //addressBar->setFocus(Qt::OtherFocusReason);
    gotoAddressBar();
    ui->tabWidget->setCurrentIndex(index);
    setWindowTitle("WildFox");
    
    ui->backButton->setEnabled(false);
    ui->forwardButton->setEnabled(false);
    
    bookmarks->createBookmarksMenu();
}


// --- NEW TAB ---
// Overloaded function. Open new browser window as in original function, but
// also returns a pointer to the WFWebView object in the new tab.
void MainWindow::newTab(WFWebView* &view) {
    newTab();
    qDebug("Passing new webview instance pointer...");
    //qDebug() << "wv: " << wv;
    view = wv;
    qDebug() << "view: " << view;
}


// --- CLOSE TAB ---
// Close the currently visible tab.
void MainWindow::closeTab() {
    if (ui->tabWidget->count() < 1) { return; }
    closeTab(ui->tabWidget->currentIndex());
}


// --- CLOSE TAB ---
// Close the indicated tab.
// TODO: store the history of the tab so that it can be restored.
void MainWindow::closeTab(int index) {
    qDebug("Close tab called");
    if (wv == 0) { return; }
    qDebug("Closing tab...");
    ui->tabWidget->removeTab(index);
    wv = (WFWebView*) ui->tabWidget->currentWidget();
    if (wv != 0) {
        setWindowTitle(wv->title() + " - WildFox");
    }
    else {
        setWindowTitle("WildFox");
    }
}


// --- NEW PAGE ---
// Called when a new page is created, inside a frameset or iframe.
void MainWindow::newPage(QWebFrame* frame) {
    connect(frame, SIGNAL(loadFinished(bool)), this, SLOT(diagnoseLoad(bool)));
}


// --- BACK ---
// Go back one page in the current tab.
void MainWindow::back() {
    if (wv == 0) { return; }
    
    wv->back();
}


// --- FORWARD ---
// Go forward one page in the current tab.
void MainWindow::forward() {
    if (wv == 0) { return; }
    
    wv->forward();
}


// --- RELOAD ---
// Reload the contents of the current tab.
void MainWindow::reload() {
    if (wv == 0) { return; }
    
    wv->stop();
    wv->reload();
}


// --- STOP ---
// Stop the loading of the currently displayed page.
void MainWindow::stop() {
    if (wv == 0) { return; }
    // TODO: check that this webview is loading something.
    
    wv->stop();
}


// --- LOAD INTERACTION ---
// Responds to the reload/stop button and acts depending on the current state.
void MainWindow::loadInteraction() {
    if (stopbutton) { stop(); }
    else { reload(); }
}


// --- BOOKMARK ADD ---
// Add the currently displayed page to the bookmarks.
// TODO: Show dialogue to select the folder to add the bookmarks to.
void MainWindow::bookmarkAdd() {
    if (wv == 0) { return; }
    
    QVariantMap bookmark;
    bookmark.insert("title", wv->title());
    bookmark.insert("url", wv->url().toString());
    bookmarks->create(bookmark);
}


// --- LOAD BOOKMARK ---
// Loads a selected bookmark into the currently active window.
void MainWindow::loadBookmark() {
    QAction* action = (QAction*) sender();
    QString url = action->data().toString();
    ui->addressBar->lineEdit()->setText(url);
    gotoURL();
    //gotoURL(url);
}


// --- LOAD BOOKMARK ---
// Loads a bookmark selected in the sidebar in the currently active window.
void MainWindow::loadBookmark(QTreeWidgetItem *item, int column) {
    QList<QVariant> data = item->data(0, Qt::UserRole).toList();
    QString url = data[0].toString();
    ui->addressBar->lineEdit()->setText(url);
    gotoURL();
    //gotoURL(url);
}


// --- DOWNLOAD CONTENT ---
// Download the content provided in a QNetworkReply in a separate thread.
void MainWindow::downloadContent(QNetworkReply* reply) {
    // Ask for path to save to.
    QString url = reply->url().toString();
    int pos = url.lastIndexOf("/");
    QString filename = url.mid(pos);
    if (filename.size() < 1) { filename = ""; }
    QString path = QFileDialog::getSaveFileName(this, tr("Save to..."), savedir.path() + filename);
    if (path.isEmpty()) { reply->deleteLater(); return; }
    savedir.setPath(path);
    
    // Launch download dialogue
    QProgressDialog* progress = new QProgressDialog(tr("Downloading %1").arg(reply->url().path()), tr("Cancel"), 0, reply->size());
    IOFile* file = new IOFile;
    file->setFileName(path);
    file->setNetworkReply(reply);
    file->open(QIODevice::WriteOnly);
    connect(reply, SIGNAL(finished()), progress, SLOT(hide()));
    connect(reply, SIGNAL(finished()), progress, SLOT(deleteLater()));
    connect(reply, SIGNAL(readyRead()), file, SLOT(readFromReply()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)), file, SLOT(readProgress(qint64,qint64)));
    connect(reply, SIGNAL(finished()), file, SLOT(terminate()));
    connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
    connect(file, SIGNAL(progress(int)), progress, SLOT(setValue(int)));
    connect(progress, SIGNAL(canceled()), file, SLOT(cancel()));
    progress->show();
    //progress->exec();
}


// --- DOWNLOAD CONTENT ---
// Download the content requested by the provided QNetworkRequest in a separate
// thread.
// FIXME: delete NAM and such after use here or make it class members.
void MainWindow::downloadContent(QNetworkRequest request) {
    QNetworkAccessManager* nam = new QNetworkAccessManager(this);
    QNetworkReply* reply = nam->get(request);
    downloadContent(reply);
}


// --- LINK HOVERED ---
// Called when the mouse cursor hovers over a link in a webpage.
void MainWindow::linkHovered(const QString &link, const QString &title, 
                             const QString &textContent) {
    ui->Ui_MainWindow::statusBar->showMessage(link);
}


// --- GO TO ADDRESS BAR ---
// Upon triggering sets the focus on the address bar and selects any text in it.
void MainWindow::gotoAddressBar() {
    ui->addressBar->lineEdit()->setFocus(Qt::ShortcutFocusReason);
    ui->addressBar->lineEdit()->selectAll();
}


// --- START SEARCH ---
// Send a search query to the selected web search engine.
// TODO: Current default is Google, make this configurable.
// Query is HTML-encoded to make it safe for transmission.
void MainWindow::startSearch() {
    QString query = ui->searchBar->text();
    if (query.isEmpty()) { return; }
    query.replace(" ", "+", Qt::CaseInsensitive);
    gotoURL("http://google.com/search?q=" + query);
}


// --- ADDRESS BAR TEXT CHANGED ---
// Called when the text in the address bar's line edit changes. Show the combo
// box's popup and fill it with 10 history items matching the text entered
// so far, sorted by popularity.
void MainWindow::addressBarTextChanged(const QString &text) {
    if (text.size() < 3) { return; }
    QString like = text;
    objects.clear();
    historydb->historyObjectsMatching(like, 12, objects);
    //historyTable->clear();
    ui->addressBar->clear();
    
    int objects_size = objects.size();
    qDebug() << "objects: " << objects_size;
    /*QTableWidgetItem* item = 0;*/
    for (int i = 0; i < objects_size; ++i) {
        //qDebug() << "i: " << i;
        //qDebug() << "qcombobox count: " << ui->addressBar->count();
        //qDebug() << "url: " << objects[i].url;
        //qDebug() << "title: " << objects[i].title;
        ui->addressBar->insertItem(i + 1, 
                                   QIcon(QWebSettings::iconForUrl(QUrl(objects[i].url))), 
                                   objects[i].title,
                                   objects[i].url
                                   );
        /*item = new QTableWidgetItem();
        item->setFlags(Qt::ItemIsEnabled);
        item->setIcon(QIcon(QWebSettings::iconForUrl(QUrl(objects[i].url))));
        item->setText(objects[i].url);
        item->setData(Qt::UserRole, objects[i].url);
        historyTable->setItem(i, 0, item);
        
        item = new QTableWidgetItem();
        item->setFlags(Qt::ItemIsEnabled);
        item->setText(objects[i].title);
        item->setData(Qt::UserRole, objects[i].url);
        historyTable->setItem(i, 1, item);*/
    }
    
    ui->addressBar->showPopup();
}


// --- HISTORY ITEM TRIGGERED ---
// Called when a history item has been triggered in the history popup of the 
// address bar.
// Loads the URL attached to the item.
void MainWindow::historyItemTriggered(int index) {
    ui->addressBar->hidePopup();
    objects.clear();
    qDebug() << "History item triggered.";
    QString url = ui->addressBar->itemData(index).toString();
    ui->addressBar->setEditText(url);
    qDebug() << "Data: " << url;
    gotoURL(url);
}


// --- TAB TITLE CHANGED ---
// Called by the WebView when the page title changes.
void MainWindow::tabTitleChanged(QString title) {
    // TODO: change main window title if current title as well
    /*QString title = wv->title();
    if (title.size() > 200) {
        title.resize(200);
    }
    
    setWindowTitle(title + " - WildFox");*/
    // obtain the index of this tab via the pointer to the WebView calling.
    QObject* w = sender();
    WFWebView* webview = (WFWebView*) w;
    if (w == 0) { qDebug("Unknown sender"); return; }
    
    int index = ui->tabWidget->indexOf(webview);
    if (index == -1) { qDebug("Tab index was -1"); return; }
    ui->tabWidget->setTabText(index, webview->title());
    if (index == ui->tabWidget->currentIndex()) {
        setWindowTitle(webview->title() + " - WildFox");
    }
}


// --- TAB ICON CHANGED ---
// Called by the WebView when the page's icon changes.
void MainWindow::tabIconChanged() {
    // First obtain the sender and cast to webview.
    WFWebView* webview = (WFWebView*) sender();
    if (webview == 0) { qDebug() << "Unknown sender."; return; }
    
    int index = ui->tabWidget->indexOf(webview);
    if (index == -1) { qDebug() << "Tab index was -1"; return; }
    ui->tabWidget->setTabIcon(index, webview->icon());
    
    bookmarks->createBookmarksMenu();
}


// --- NEW HISTORY TAB ---
// Open a new tab and the history dialog.
void MainWindow::newHistoryTab() {
    newTab();
    openHistoryDialog();
}


// --- OPEN HISTORY DIALOG ---
// Open the history dialogue.
void MainWindow::openHistoryDialog() {
    QString url;
    HistoryDialog dialog(&url);
    int r = dialog.exec();
    if (r == QDialog::Accepted) {
        qDebug() << "Accepted.";
        // open URL in the current tab, if URL string is non-empty
        if (url.isEmpty()) { return; }
        qDebug() << "Load URL...";
        gotoURL(url);
    }
}


// --- CLOSE EVENT ---
// Reeimplements the close event function of QWidget to save state.
void MainWindow::closeEvent(QCloseEvent* event)  {
     settings->setValue("geometry", saveGeometry());
     settings->setValue("windowState", saveState());
     settings->setValue("bookmarkSidebar", ui->bookmarksTree->isVisible());
     QMainWindow::closeEvent(event);
 }


<|start_filename|>bookmarks.h<|end_filename|>
/*
  bookmarks.h - bookmarks definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - Definition of the bookmarks functions class.
        
  2012/03/20, <NAME>
  (c) Nyanko.ws
*/

#ifndef BOOKMARKS_H
#define BOOKMARKS_H

#include <QSqlDatabase>
#include <QVariantMap>
#include <QDir>
#include <QDebug>
#include <QSqlError>
#include <QMenu>


struct BookmarkData {
    int id;
    int type;
    int fk;
    int parent;
    int position;
    QString title;
    int keyword_id;
    QString folder_type;
    int dateAdded;
    int lastModified;
    QString guid;
};


struct MenuItem {
    int id;
    QMenu* item;
};


struct ActionItem {
    int id;
    QAction* action;
};


enum {
    TYPE_BOOKMARK = 0,
    TYPE_FOLDER = 1
};

class MainWindow;
#include "mainwindow.h"

class Bookmarks : public QObject {
    Q_OBJECT
    
public:
    Bookmarks(MainWindow* window);
    ~Bookmarks();
    
    void createBookmarksMenu();
    QVariantMap create(QVariantMap bookmark);
    
public slots:
    void deleteBookmark();
    
signals:
    void bookmarkCreated();
    
private:
    void recursiveTreeDescent(QMenu* menu, QTreeWidgetItem* parentfolder, int parentID);
    
    QSqlDatabase db;
    QMultiMap<int, MenuItem> menus;
    QMultiMap<int, ActionItem> actions;
    MainWindow* mw;
    QString storagePath;    
    QMenu* contextmenu;
};

#endif // BOOKMARKS_H


<|start_filename|>cookiemanagedialog.h<|end_filename|>
/*
  cookiemanagedialog.h - Cookie Manage dialog definition file of WildFox-Mimic.
  
  Revision 0
  
  Notes:
        - 
        
  2012/02/09, <NAME>
  (c) Nyanko.ws
*/


#ifndef COOKIEMANAGEDIALOG_H
#define COOKIEMANAGEDIALOG_H

#include <QDialog>
#include <QSqlDatabase>
#include <QMultiMap>
#include <QNetworkCookie>
#include <QDateTime>


struct CookieData {
    QString name;
    QString value;
    QString host; 
    QString path;
    QDateTime expiry;
    bool isSecure;
    bool isHttpOnly;
};

namespace Ui {
class CookieManageDialog;
}

class CookieManageDialog : public QDialog {
    Q_OBJECT
    
public:
    explicit CookieManageDialog(QSqlDatabase* db, QMultiMap<QString, QNetworkCookie>* buffer, QWidget *parent = 0);
    ~CookieManageDialog();
    
public slots:
    void showCookieDetails();
    void deleteCookie();
    void deleteAllCookies();
    void close();
    
private:
    Ui::CookieManageDialog* ui;
    
    QSqlDatabase* db;
    QMultiMap<QString, QNetworkCookie>* cookiebuffer;
    QString baseDomain;
    QList<CookieData> cookiedata;
};

#endif // COOKIEMANAGEDIALOG_H


<|start_filename|>chrome/chromebookmarks.cpp<|end_filename|>
/*
  chromebookmarks.cpp - Chrome JS ext API implementation file of WildFox-Mimic.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2012/02/21, <NAME>
  (c) Nyanko.ws
*/


#include "chromebookmarks.h"


// --- CONSTRUCTOR ---
ChromeBookmarks::ChromeBookmarks(Bookmarks *bookmarks) {
    bm = bookmarks;
}


// --- DECONSTRUCTOR ---
ChromeBookmarks::~ChromeBookmarks() {
    //
}


// --- CREATE ---
QVariantMap ChromeBookmarks::create(QVariantMap bookmark, QString callback) {
    QVariantMap map = bm->create(bookmark);
    return map;
}


<|start_filename|>historydialog.h<|end_filename|>
/*
  historydialog.h - Declaration of HistoryDialog class.
  
  Revision 0
  
  Notes:
        - 
        
  2013/05/16, <NAME>
  (c) Nyanko.ws
*/


#ifndef HISTORYDIALOG_H
#define HISTORYDIALOG_H

#include <QDialog>
#include <QListWidget>
#include <QListWidgetItem>

#include "historydatabase.h"

namespace Ui {
    class HistoryDialog;
}

class HistoryDialog : public QDialog {
    Q_OBJECT
    
public:
    explicit HistoryDialog(QString* url, QWidget *parent = 0);
    ~HistoryDialog();
    
private slots:
    void editingTriggered(QString text);
    void accepted();
    void itemActivated(QListWidgetItem* item);
    
private:
    Ui::HistoryDialog* ui;
    QString* url;
    HistoryDatabase* historydb; // the history database
    QList<HistoryObject> objects;   // Objects being shown in address bar popup.
};

#endif // HISTORYDIALOG_H


<|start_filename|>addressbardelegate.cpp<|end_filename|>
/*
  addressbardelegate.cpp - Address Bar Delegate implementation file of WildFox.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2013/04/28, <NAME>
  (c) Nyanko.ws
*/


#include "addressbardelegate.h"

#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QDebug>


// --- CONSTRUCTOR ---
AddressBarDelegate::AddressBarDelegate(QObject *parent) :
    QStyledItemDelegate(parent) {
    //
}


// --- PAINT ---
// Paints the view.
// Takes a rich text format string and inserts it into a QTextDocument. Then uses the
// drawContents function of the QTextDocument instance to paint on the provided rectangle
// in option using the provided painter.
void AddressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, 
                               const QModelIndex &index) const {
    qDebug() << "Custom delegate called...";
    qDebug() << "Index text: " << index.data().toString();
    
    painter->save();
    QTextDocument doc;
    doc.setHtml(index.data().toString());
    QAbstractTextDocumentLayout::PaintContext context;
    doc.setPageSize(option.rect.size());
    painter->translate(option.rect.x(), option.rect.y());
    doc.documentLayout()->draw(painter, context);
    painter->restore();
}


<|start_filename|>tabhistory.h<|end_filename|>
/*
  tabhistory.h - declaration of WildFox's TabHistory class.
  
  Revision 0
  
  Notes:
        - 
        
  2013/06/01, <NAME>
  (c) Nyanko.ws
*/


#ifndef TABHISTORY_H
#define TABHISTORY_H

#include <QObject>
#include <QIcon>
#include <QUrl>
#include <QDateTime>


struct TabHistoryItem {
    QIcon icon;
    QUrl originalUrl;
    QUrl url;
    QString title;
    QDateTime lastVisited;
};


class TabHistory : public QObject {
    Q_OBJECT
public:
    explicit TabHistory(QObject *parent = 0);
    
    void clear();
    
    QList<TabHistoryItem> items() const;
    QList<TabHistoryItem> backItems(int maxItems) const;
    QList<TabHistoryItem> forwardItems(int maxItems) const;
    
    bool canGoBack() const;
    bool canGoForward() const;
    
    void back();
    void forward();
    void goToItem(const TabHistoryItem &item);
    
    TabHistoryItem backItem() const;
    TabHistoryItem currentItem() const;
    TabHistoryItem forwardItem() const;
    TabHistoryItem itemAt(int i) const;
    
    int currentItemIndex() const;
    
    int count() const;
    
    int maximumItemCount() const;
    void setMaximumItemCount(int count);
    
signals:
    
public slots:
    
private:
    QList<TabHistoryItem> historyItems;    
};

#endif // TABHISTORY_H


<|start_filename|>wfwebhistoryinterface.cpp<|end_filename|>
/*
  wfwebhistoryinterface.h - declaration of WildFox's WFWebHistoryInterface class.
  
  Revision 0
  
  Features:
        - 
        
  Notes:
        - 
        
  2013/04/04, <NAME>
  (c) Nyanko.ws
*/


#include "wfwebhistoryinterface.h"

#include <QDebug>


// --- CONSTRUCTOR ---
WFWebHistoryInterface::WFWebHistoryInterface(/*QObject *parent*/) /*: QWebHistoryInterface(parent)*/ {
    history = HistoryDatabase::getInstance(); // obtain singleton instance
}


// --- ADD HISTORY ENTRY ---
// Called by WebKit to add another url to the list of visited pages.
void WFWebHistoryInterface::addHistoryEntry(const QString &url) {
    //history.addHistoryEntry(url);
}


// --- HISTORY CONTAINS ---
// Called by the WebKit engine to query whether a certain url has been visited 
// by the user already. Returns true if the url is part of the history of 
// visited links; otherwise returns false.
bool WFWebHistoryInterface::historyContains(const QString &url) const {
    //qDebug() <<  "WebHistoryInterface URL:" << url;
    return history->historyContains(url);
}


<|start_filename|>wfwebview.h<|end_filename|>
/*
  wfwebview.h - Definition file of WildFox-Mimic WFWebView class.
  
  Revision 0
  
  Notes:
        - 
        
  2011/11/22, <NAME>
  (c) Nyanko.ws
*/


#ifndef WFWEBVIEW_H
#define WFWEBVIEW_H

#include "mainwindow.h"
#include <QWebView>
#include "wfwebpage.h"

class MainWindow;

class WFWebView : public QWebView {
    Q_OBJECT
    
public:
    WFWebView();
    
    //void setTabManager(TabManager* tabman);
    //void setUIParent(MainWindow *parent);
    QWebView* createWindow(QWebPage::WebWindowType type);
    
protected:
    //void contextMenuEvent(QContextMenuEvent*);
    
private:
    //TabManager* tabmanager;
    MainWindow* uip;
};

#endif // WFWEBVIEW_H
