/*****************************************************************************
 * Copyright (C) 2004-2009 Christoph Thielecke <crissi99@gmx.de>             *
 *                                                                           *
 * This program is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published by      *
 * the Free Software Foundation; either version 2 of the License, or         *
 * (at your option) any later version.                                       *
 *                                                                           *
 * This package 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 General Public License for more details.                              *
 *                                                                           *
 * You should have received a copy of the GNU General Public License         *
 * along with this package; if not, write to the Free Software               *
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA *
 *****************************************************************************/

#ifndef KVPNC_H
#define KVPNC_H

#include <QProcess>

#include <QtCore/QDateTime>
#include <QtCore/QFile>
#include <QtCore/QPoint>
#include <QtCore/QSize>
#include <QtCore/QTimer>

#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusContext>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusReply>
#include <QtGui/QCloseEvent>
#include <QtGui/QLabel>
#include <QtGui/QPixmap>
#include <QtGui/QWidget>
#include <QtGui/QMenu>
#include <QPoint>

#include <QStringList>
#include <QTextStream>

#include <kprocess.h>
#include <kptyprocess.h>
#include <kaction.h>
#include <kapplication.h>
#include <kfeedback.h>
#include <kmainwindow.h>
#include <knotification.h>
#include <knotifyconfigwidget.h>
#include <ktoggleaction.h>
#include <kxmlguiwindow.h>
#include <kptydevice.h>

#include "kvpncconfig.h"
#include "kvpnckicker.h"
#include "mainview.h"
#include "networkinterface.h"
#include "openvpnmanagementhandler.h"
#include "preferencesdialog.h"
#include "toolinfo.h"
#include "vpnaccountdata.h"
#include "utils.h"

// ID for statusbar
#define ID_STATUS_MSG 1
#define ID_CONNECTION_MSG 2
#define ID_FLASH_MSG 3

class QProcess;
/**
 * KVpnc main class
 */
class KVpnc : public KXmlGuiWindow, private QDBusContext
{
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "kde.org.kvpnc")

public:
    /**
     * Constructor
     * @param parent Parent widget
     * @param name Name of the Mainwindow
     */
    KVpnc(KApplication *parent, QWidget* parentWidget = 0);

    /**
     * Destructor
     */
    ~KVpnc();

protected:
    /**
     * init the actions
     */
    void initAction();

    /**
     * init the main view
     */
    void initView();

    /**
     * init the statusbar
     */
    void initStatusbar();

    /**
     * init the kicker system tray icon
     */
    void initDockWindow();

    /**
     * sets the gui status
     * @param status The status that will be set
     */
    void setGuiStatus(int status);

    /**
     * terminates the connection
     * @param proc the connect process
     */
    void terminateConnection(QProcess *proc);

    /**
     * called when quit requested
     */
    virtual bool queryExit();

    void saveProperties(KConfigGroup &);
    void readProperties(const KConfigGroup &);

public:
    void restore(KConfig *config, int i);
    void restore();

    /**
     * return the user id of the certificate
     *  @param Cert certificate from which should be extracted
     * @param user true if user id, false if issuer id
     */
    QString getX509CertificateID(QString Cert, bool user);

    void profileAddedOrDeleted();
    bool setVirtualIP();

private:
    KApplication *parent;
    QStringList *env;

    QDBusMessage reply;
    // QDBusConnection connection;

    KVpncConfig *GlobalConfig;
    KVpncKicker* KVpncDock; //< kicker menu
    KAction* ConnectAction; //< connect action
    KAction* DisconnectAction; //< disconnect action
    KAction *NewSessionAction;
    KAction *SaveSessionAction;
    KAction *DeleteSessionAction;
    KAction *RenameSessionAction;
    KAction *ImportSessionAction;
    KAction *ImportOpenvpnProfileAction;
    KAction *ExportOpenvpnProfileAction;
    KAction *ImportFreeswanProfileAction;
    KAction *ImportFritzboxProfileAction;
    KAction *ImportKvpncSettingsAction;
    KAction *ExportKvpncSettingsAction;
    KAction *ImportCertAction;
    KAction *SelectAction; //< line select action
    KAction *ProfileManagerAction;
    KAction *NewProfileWizardAction;
    KAction *HelpAction;
    KAction *PrefAction;
    KAction *DonateAction;
    KAction *VisitHomepageAction;
    KAction *SendFeedbackMailAction;
    KAction *PreferencesAction; //< show preferences dialog
    KAction *ManageCiscoCertAction; //< show cisco cert manager
    KAction *CiscoCertEnrollmentAction; //< show cisco cert enrollment dialog
    KToggleAction *ToolsInfoAction;
    KToggleAction *VpnTypesInfoAction;
    KToggleAction *LogViewerAction;
    KToggleAction *ShowToolbarAction; //< toggle toolbar on/off
    KToggleAction *ShowStatusbarAction; //< toggle statusbar on/off
    KToggleAction *DebugconsoleAction; //< toggle debug console
    KToggleAction *GenerateOpenvpnKeyAction; //< generate OpenVPN key
    MainView* mw; //< Main gui
    QTimer timer;
    QTimer durationTimer; //< timer for counting connection time
    QTimer IpsecWhackStatusTimer; //< getting ipsec status periodically
    QTimer L2tpWaitForPppUpTimer; //< getting ppp device
    int connectCounter; //< counter for connecting
    int RacoonctlConnectCounter; //<< counter for waiting of adminsock
    int sec, min, hour;
    int racoon_tunnel_state; // 0 => no tunnel, 1 => first tunnel, 2 => second tunnel
    int prevConnectionState; //< needed for setGuiStatus(), holds previous state before disconnect (connected, connecting)

    bool cancelClicked;
    bool deviceaddrstr2addr;
    bool pingtest;
    bool getUserID;
    bool X509CertificateExtractRunning;
    bool X509CertificateExtractUser;
    bool setVirtualIPSuccess;
    bool AuthRetry;
    bool quitFromKicker;
    bool shutdownIsCalled;
    bool stopContinue; //< if something happens that causes to abort now
    bool ciscoVpncRunning; //< true if vpnclient is started and cipsec0 is up
    bool showProfilesOnly; //< if true only the profiles will shown in preferencesdialog
    bool IpsecStartingInProgress;
    bool IpsecGotError;
    bool IpsecPhase1Up;
    bool IpsecPhase2Up;
    bool IpsecStatusCheck;
    bool pppdHasReplacedefaultrouteSupport;
    bool sendingVpncConfigInProgress; // flag to hide config when read from pty device
    bool pppdCapabilitiesCollected; // flag if the caps already fetched

    QString OldDefaultroute;
    QString VpncConnectScript;
    QString VpncDisconnectScript;
    QString tmpPath;
    QString ProcessMsg_connect;
    QString ProcessMsg_disconnect;
    QString deviceaddrstr;
    QString deviceaddr;
    QString tmpInterface;
    QString LocalIP;
    QString VpncGateway;
    QString PptpGateway;
    QString VpncScript;
    QString issuerID; // for id extract
    QString userID;   // for id extract
    QString TunnelInterfaceIP;
    QString TmpDns1;
    QString TmpDns2;
    QString VpncDevice;
    QString CiscoVpncDevice;
    QString L2tpPppDevice;
    QString PppdDevice;
    QString OpenvpnDevice;
    QString SshDevice;
    QString IpsecType; //< openswan, strongswan, freeswan
    QString Pkcs11PIN;
    QString vpncConfig;
    QString PrettyTypeString;
    QString PrettyStatusMessage;

    KPtyProcess *VpncProcess;
    QProcess *DisconnectProcess;
    KProcess *CiscoVpncProcess; //< vpnclient
    QProcess *RacoonProcess; //< racoon
    QProcess *RacoonHelperProcess;
    QProcess *IpsecProcess; //< freeswan/openswan/strongswan
    QProcess *IpsecStartProcess;
    QProcess *IpsecWhackProcess; //< ipsec whack --initate
    QProcess *IpsecWhackStatusProcess; //< ipsec whack --status
    QProcess *IpsecWhackListenProcess; //< ipsec whack --listen
    QProcess *IpsecWhackDeleteProcess; //< ipsec whack --delete
    QProcess *PingProcess;
    QProcess *RacoonTailProcess;
    QProcess *RacoonctlProcess; //< racoonctl
    QProcess *X509CertificateExtractProcess;
    QProcess *PptpProcess;
    QProcess *OpenvpnProcess;
    QProcess *CmdBeforeConnectProcess;
    QProcess *CmdBeforeDisconnectProcess;
    QProcess *CmdAfterConnectedProcess;
    QProcess *CmdAfterDisconnectedProcess;
    QProcess *RouteProcess;
    QProcess *SetVirtualIPProcess;
    QProcess *ConnectionStatusCheckProcess;
    QProcess *TestCiscoVpncProcess;
    QProcess *L2tpdProcess;
    QProcess *OpenL2tpProcess;
    QProcess *VtundProcess;
    QProcess *StartStopOpenl2tpProcess;
    QProcess *startStopIpsecProcess;
    KPtyProcess *SshProcess;

    KPtyDevice *VpncPty;
    KPtyDevice *SshPty;

    int TimeOutProcess; //< for timeout
    int ConnectingProcess; //< for killing process
    QPixmap connectingStatusPixmap;
    QPixmap disconnectedStatusPixmap;
    QPixmap connectedStatusPixmap;

    QLabel *statusColorLabel;
    QMenu *QuickConnectMenu;

    OpenvpnManagementHandler *managementhandler ;
    KFeedbackDialog *FeedbackDialog;

    QString L2tpdBufferStdoutString;
    QString L2tpdBufferStderrString;

    PreferencesDialog *prefDlg;

public slots:
    /**
     * setup KVpnc
     */
    void slotSettings();

    /**
     * show/hide toolbar
     */
    void slotShowToolbar();

    /**
     * show/hide statusbar
     */
    void slotShowStatusbar();

    /**
     * configure key bindings
     */
    void slotKeyBindings();

    /**
     * configure toolbars
     */
    void slotConfigToolbars();

    void slotConfigNotifications();

    /**
     * Slot for status message
     * @param text The text that will be set
     * @param id What type its is
     */
    void slotStatusMsg(const QString &text, int id = ID_STATUS_MSG);

    void connectClicked();
    void disconnectClicked();
    void saveSessionClicked();
    void newSessionClicked();
    void deleteSessionClicked();
    void renameSessionClicked();
    void sessionToggled(const QString&);
    void helpClicked();
    void toolsInfoClicked();
    void vpnTypesInfoClicked();
    void donateClicked();
    void visitHomepageClicked();
    void saveGuiOptions();
    void showNewProfileWizardClicked();

private slots:

    /**
     * called if close clicked
     * @param e the event which happen
     */
    void closeEvent(QCloseEvent* e);

    bool queryClose();
    void shutdownCalled();
    void slotCancelClicked();
    void slotConnectTimedOut();
    void slotDurationEvent();
    void showDockTooltip(const QPoint &);
    void readOutputFrom_vpnc();
    void handleOutputFrom_vpnc(QString msg, OutputMsg::MsgType type);
    void readOutputFrom_ciscovpnc();
    void readFromStdout_disconnect();
    void readFromStderr_disconnect();
    void readFromStdout_racoon();
    void readFromStderr_racoon();
    void readFromStdout_racoon_helper();
    void readFromStderr_racoon_helper();
    void readFromStdout_ipsec();
    void readFromStderr_ipsec();
    void readFromStdout_ipsecwhack();
    void readFromStderr_ipsecwhack();
    void readFromStdout_ipsecwhacklisten();
    void readFromStderr_ipsecwhacklisten();
    void readFromStdout_ipsecwhackstatus();
    void readFromStderr_ipsecwhackstatus();
    void readFromStdout_ipsecwhackdelete();
    void readFromStderr_ipsecwhackdelete();
    void readFromStdout_pptp();
    void readFromStderr_pptp();
    void readFromStdout_l2tpd();
    void readFromStderr_l2tpd();
    void processStdout_l2tpd(QString msg);
    void processStderr_l2tpd(QString msg);
    void readFromStdout_openl2tp();
    void readFromStderr_openl2tp();
    void readFromStdout_startstopOpenl2tp();
    void readFromStderr_startstopOpenl2tp();
    void checkL2tpPppUp();
    void readOutput_openvpn();
    void readFromStdout_vtun();
    void readFromStderr_vtun();
    void readFromStdout_ssh();
    void readFromStderr_ssh();
    void handleOutputFrom_ssh(QString msg, OutputMsg::MsgType type);
    void readFromStdout_executeCommandBeforeConnect();
    void readFromStderr_executeCommandBeforeConnect();
    void readFromStdout_executeCommandAfterConnect();
    void readFromStderr_executeCommandAfterConnect();
    void readFromStdout_executeCommandBeforeDisconnect();
    void readFromStderr_executeCommandBeforeDisconnect();
    void readFromStdout_executeCommandAfterDisconnect();
    void readFromStderr_executeCommandAfterDisconnect();

    void readFromStdout_tail_racoon();
    void readFromStderr_tail_racoon();
    void readFromStdout_racoonctl();
    void readFromStderr_racoonctl();
    void readFromStdout_ping();
    void readFromStderr_ping();
    void readFromStdout_route();
    void readFromStderr_route();
    void readFromStdout_getX509CertificateID();
    void readFromStderr_getX509CertificateID();
    void readFromStdout_setVirtualIP();
    void readFromStderr_setVirtualIP();
    void readFromStdout_connectionStatusCheck();
    void readFromStderr_connectionStatusCheck();
    void readCiscoVpncTestProcessOutput();
    void readFromPty_ssh();
    void readFromPty_vpnc();
    void quitCalled();
    void quitCalledKicker();
    void pptpProcessExited(int, QProcess::ExitStatus);
    void openvpn_exited(int, QProcess::ExitStatus);
    void vtun_exited(int, QProcess::ExitStatus); //< vtund has been exited
    void ipsecwhack_exited(int, QProcess::ExitStatus); //< ipsec whack has been exited
    void IpsecWhackStatusProcessExited(int, QProcess::ExitStatus);
    void racoonctlExited(int, QProcess::ExitStatus);
    void prepareL2tpd(bool do_auth=false); //< write l2tpd conf etc.
    void start_ipsec_initiate();
    void doAddRemoveVirtualIp(QString action);

    void importProfileClicked(); //< PCF import
    void importIpsecProfileClicked();
    void importFritzboxProfileClicked();

    void importKvpncSettingsClicked();
    void exportKvpncSettingsClicked();

    void importOpenvpnProfileClicked(); //< OpenVPN config file import
    void doRacoon(int, QProcess::ExitStatus);
    void stopRacoon();
    void doRoutePptp();
    void addRouteIpsec();
    void delRouteIpsec();
    void doTailRacoonLog();
    void doIptablesRacoon();
    void doIptablesFreeswan();
    void addRouteRacoon();
    void delRouteRacoon();
    void doPingKickupTunnel();
    void removeIptablesRacoon();
    void removeIptablesFreeswan();
    void removeSetkey();
    void connectionEnded();
    void doPingTest();
    void pingTestExited(int, QProcess::ExitStatus);
    void sshExited(int, QProcess::ExitStatus);
    void vpncStarted();
    void ipsecStarted(int, QProcess::ExitStatus);
    void ipsecPhase2Established();
    void checkIpsecWhackStatus();
    void addIpsecConnection();
    void racoonStarted();
    void pppdStarted(int, QProcess::ExitStatus);
    void openvpnStarted(int, QProcess::ExitStatus);
    void importCertClicked();
    void manageCiscoCertClicked();
    void enrollCiscoCertClicked();
    void showProfileManagerClicked();
    void executeCommandBeforeConnect();
    void executeCommandAfterConnect();
    void executeCommandBeforeDisconnect();
    void executeCommandAfterDisconnect();
    void setFirewallAfterConnect();
    void setFirewallBeforeDisconnect();
    void slotConnecting();
    void toggleDebugConsole();
    void addAdditionalNetworkRoutes();
    void removeAdditionalNetworkRoutes();
    void showLogViewer();
    void doQuickConnect(QAction *);
    void startConnectionStatusCheck();
    void generateOpenvpnKey();
    void preserveNetworkEnvironment(); //< save route and resolv.conf
    void restoreNetworkEnvironment(); //< restore route and resolv.conf
    void backupIpsecSystemConfig(); // backup ipsec.conf and  ipsec.secrets
    void backupDefaultRoute();
    void exportOpenvpnProfileClicked();
    void addFeatureList(KFeedbackQuestion * question);
    void sendFeedbackMail();
    void feedbackMailSent();
    void start_l2tpd();
    bool checkCiscoVpncStatus();
    void startCiscoVpnc();
    void startStopIpsec(bool stop = false, bool silent = false);
    void startStopOpenl2tp(bool stop = false, bool silent = false);

signals:
    void L2tpdStdoutRecieved();
    void L2tpdStderrRecieved();
    void newProfileCreated(QString Name);

public:
    void importOpenvpnProfileClicked(QString file); //< OpenVPN config file import
    void importProfileClicked(QString file); //< PCF import

    bool backupResolvConf();
    bool restoreResolvConf();

private:
    void waitForFinished(QProcess *process, int refreshtime, QString refreshmsg=""); //< this waits while process process is running refreshes every refreshtime, if refreshmsg is not empty its displayed

public Q_SLOTS:
    Q_SCRIPTABLE  QString getVersion();
    Q_SCRIPTABLE void doConnect();
    Q_SCRIPTABLE void doDisconnect();
    Q_SCRIPTABLE uint getConnectedTime();
    Q_SCRIPTABLE QString getStatus();
    Q_SCRIPTABLE QString getCurrentProfile();
    Q_SCRIPTABLE void setProfile(QString profilename);
    Q_SCRIPTABLE void createNewProfile();
    Q_SCRIPTABLE void createNewProfileWithWizard();
    Q_SCRIPTABLE void deleteCurrentProfile();
    Q_SCRIPTABLE void openPreferences();
    Q_SCRIPTABLE void doImportCert();
    Q_SCRIPTABLE void doImportPcf();
    Q_SCRIPTABLE void doImportPcf(QString file);
    Q_SCRIPTABLE void doImportOpenvpnConfig();
    Q_SCRIPTABLE void doImportOpenvpnConfig(QString file);
    Q_SCRIPTABLE QStringList profiles();
    Q_SCRIPTABLE QStringList toolinfo();
    Q_SCRIPTABLE void doQuit();
    Q_SCRIPTABLE void doGenerateOpenvpnKey();
    Q_SCRIPTABLE void doSendFeedbackMail();
    Q_SCRIPTABLE QStringList getProfileTypes();
};

#endif
