Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • release/201811
  • release/201808
  • releases/beta1
  • packaging
  • releases/alpha
  • 1.0.0
  • 0.2.0
  • 0.1.0
21 results

MinimalHistoryBackend.mm

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    MinimalHistoryBackend.mm 10.58 KiB
    /************************************************************************************
     *   Copyright (C) 2014-2015 by Savoir-Faire Linux                                       *
     *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
     *                                                                                  *
     *   This library is free software; you can redistribute it and/or                  *
     *   modify it under the terms of the GNU Lesser General Public                     *
     *   License as published by the Free Software Foundation; either                   *
     *   version 2.1 of the License, or (at your option) any later version.             *
     *                                                                                  *
     *   This library is distributed in the hope that it will be useful,                *
     *   but WITHOUT ANY WARRANTY; without even the implied warranty of                 *
     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU              *
     *   Lesser General Public License for more details.                                *
     *                                                                                  *
     *   You should have received a copy of the GNU Lesser General Public               *
     *   License along with this library; if not, write to the Free Software            *
     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
     ***********************************************************************************/
    #import "minimalhistorybackend.h"
    
    #import <Cocoa/Cocoa.h>
    
    //Qt
    #import <QtCore/QFile>
    #import <QtCore/QDir>
    #import <QtCore/qlist.h>
    #import <QtCore/QHash>
    #import <QtWidgets/QApplication>
    #import <QtCore/QStandardPaths>
    #import <collectioneditor.h>
    
    //Ring
    #import <call.h>
    #import <account.h>
    #import <person.h>
    #import <contactmethod.h>
    #import <categorizedhistorymodel.h>
    
    #import "../Constants.h"
    
    class MinimalHistoryEditor : public CollectionEditor<Call>
    {
    public:
        MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent);
        virtual bool save       ( const Call* item ) override;
        virtual bool remove     ( const Call* item ) override;
        virtual bool batchRemove(const QList<Call*> contacts) override;
        virtual bool edit       ( Call*       item ) override;
        virtual bool addNew     ( const Call* item ) override;
        virtual bool addExisting( const Call* item ) override;
    
    private:
        virtual QVector<Call*> items() const override;
    
        //Helpers
        void saveCall(QTextStream& stream, const Call* call);
        bool regenFile(const Call* toIgnore);
    
        //Attributes
        QVector<Call*> m_lItems;
        MinimalHistoryBackend* m_pCollection;
    };
    
    MinimalHistoryEditor::MinimalHistoryEditor(CollectionMediator<Call>* m, MinimalHistoryBackend* parent) :
    CollectionEditor<Call>(m),m_pCollection(parent)
    {
    
    }
    
    MinimalHistoryBackend::MinimalHistoryBackend(CollectionMediator<Call>* mediator) :
    CollectionInterface(new MinimalHistoryEditor(mediator,this)),m_pMediator(mediator)
    {
    
    }
    
    MinimalHistoryBackend::~MinimalHistoryBackend()
    {
    
    }
    
    void MinimalHistoryEditor::saveCall(QTextStream& stream, const Call* call)
    {
        const QString direction = (call->direction()==Call::Direction::INCOMING)?
        Call::HistoryStateName::INCOMING : Call::HistoryStateName::OUTGOING;
    
        const Account* a = call->account();
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CALLID          ).arg(call->historyId()                     );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_START ).arg(call->startTimeStamp()         );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_STOP  ).arg(call->stopTimeStamp()          );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::ACCOUNT_ID      ).arg(a?QString(a->id()):""          );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DISPLAY_NAME    ).arg(call->peerName()               );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::PEER_NUMBER     ).arg(call->peerContactMethod()->uri() );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DIRECTION       ).arg(direction                      );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::MISSED          ).arg(call->isMissed()               );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::RECORDING_PATH  ).arg(call->recordingPath()          );
        stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_USED    ).arg(false                          );//TODO
        if (call->peerContactMethod()->contact()) {
            stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_UID  ).arg(
                                                                                        QString(call->peerContactMethod()->contact()->uid())
                                                                                        );
        }
        stream << "\n";
        stream.flush();
    }
    
    bool MinimalHistoryEditor::regenFile(const Call* toIgnore)
    {
        QDir dir(QString('/'));
        dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
    
        QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
        if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) {
            QTextStream stream(&file);
            for (const Call* c : CategorizedHistoryModel::instance()->getHistoryCalls()) {
                if (c != toIgnore)
                    saveCall(stream, c);
            }
            file.close();
            return true;
        }
        return false;
    }
    
    bool MinimalHistoryEditor::save(const Call* call)
    {
        if (call->collection()->editor<Call>() != this)
            return addNew(call);
    
        return regenFile(nullptr);
    }
    
    bool MinimalHistoryEditor::remove(const Call* item)
    {
        mediator()->removeItem(item);
        return regenFile(item);
    }
    
    bool MinimalHistoryEditor::batchRemove(const QList<Call*> calls) {
        QFile::remove(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "history.ini");
        return YES;
    }
    
    bool MinimalHistoryEditor::edit( Call* item)
    {
        Q_UNUSED(item)
        return false;
    }
    
    bool MinimalHistoryEditor::addNew(const Call* call)
    {
        QDir dir(QString('/'));
        dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + QString());
    
        if ((call->collection() && call->collection()->editor<Call>() == this)  || call->historyId().isEmpty()) return false;
        //TODO support \r and \n\r end of line
        QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/')+"history.ini");
    
        if ( file.open(QIODevice::Append | QIODevice::Text) ) {
            QTextStream streamFileOut(&file);
            saveCall(streamFileOut, call);
            file.close();
    
            const_cast<Call*>(call)->setCollection(m_pCollection);
            addExisting(call);
            return true;
        }
        else
            qWarning() << "Unable to save history";
        return false;
    }
    
    bool MinimalHistoryEditor::addExisting(const Call* item)
    {
        m_lItems << const_cast<Call*>(item);
        mediator()->addItem(item);
        return true;
    }
    
    QVector<Call*> MinimalHistoryEditor::items() const
    {
        return m_lItems;
    }
    
    QString MinimalHistoryBackend::name () const
    {
        return QObject::tr("Minimal history backend");
    }
    
    QString MinimalHistoryBackend::category () const
    {
        return QObject::tr("History");
    }
    
    QVariant MinimalHistoryBackend::icon() const
    {
        return QVariant();
    }
    
    bool MinimalHistoryBackend::isEnabled() const
    {
        return true;
    }
    
    bool MinimalHistoryBackend::load()
    {
        // get history limit from our preferences set
        NSInteger historyLimit = [[NSUserDefaults standardUserDefaults] integerForKey:Preferences::HistoryLimit];
    
        QFile file(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') +"history.ini");
        if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
            QMap<QString,QString> hc;
            while (!file.atEnd()) {
                QByteArray line = file.readLine().trimmed();
    
                //The item is complete
                if ((line.isEmpty() || !line.size()) && hc.size()) {
                    Call* pastCall = Call::buildHistoryCall(hc);
                    if (pastCall->peerName().isEmpty()) {
                        pastCall->setPeerName(QObject::tr("Unknown"));
                    }
    
                    if(daysSince(pastCall->startTimeStamp()) < historyLimit) {
                        pastCall->setRecordingPath(hc[ Call::HistoryMapFields::RECORDING_PATH ]);
                        pastCall->setCollection(this);
    
                        editor<Call>()->addExisting(pastCall);
                    }
                    hc.clear();
                }
                // Add to the current set
                else {
                    const int idx = line.indexOf("=");
                    if (idx >= 0)
                        hc[line.left(idx)] = line.right(line.size()-idx-1);
                }
            }
            return true;
        }
        else
            qWarning() << "History doesn't exist or is not readable";
        return false;
    }
    
    int MinimalHistoryBackend::daysSince(time_t timestamp)
    {
        NSDate *fromDate;
        NSDate *toDate;
    
        NSDate* fromDateTime = [NSDate dateWithTimeIntervalSince1970:timestamp];
    
        NSCalendar *calendar = [NSCalendar currentCalendar];
    
        [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
                     interval:NULL forDate:fromDateTime];
        [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
                     interval:NULL forDate:[NSDate date]];
    
        NSDateComponents *difference = [calendar components:NSCalendarUnitDay
                                                   fromDate:fromDate toDate:toDate options:0];
    
        return [difference day];
    }
    
    bool MinimalHistoryBackend::reload()
    {
        return false;
    }
    
    FlagPack<CollectionInterface::SupportedFeatures> MinimalHistoryBackend::supportedFeatures() const
    {
        return (FlagPack<SupportedFeatures>) (
                                                         CollectionInterface::SupportedFeatures::NONE  |
                                                         CollectionInterface::SupportedFeatures::LOAD  |
                                                         CollectionInterface::SupportedFeatures::CLEAR |
                                                         CollectionInterface::SupportedFeatures::REMOVE|
                                                         CollectionInterface::SupportedFeatures::ADD   );
    }
    
    bool MinimalHistoryBackend::clear()
    {
        editor<Call>()->batchRemove(items<Call>().toList());
        QList<Call*> calls = items<Call>().toList();
        for(int i = 0 ; i < calls.count() ; ++i) {
            CategorizedHistoryModel::instance()->deleteItem(calls[i]);
        }
        return true;
    }
    
    QByteArray MinimalHistoryBackend::id() const
    {
        return "mhb";
    }