#!/usr/bin/env python

import os
import re
import sys
import time                
import dbus
import logging

##############################################################
#    smscon - remote control utility                         #
##############################################################

VERSION  = '0.5-5'

##############################################################

# check if run as root
if os.geteuid() != 0:
    print 'ERROR: smscon must run as "root".'
    sys.exit(1)

##############################################################

Path                         = '/opt/smscon/'
BootPath                     = '/etc/event.d/'

DaemonFile                   = 'smscon_daemon'
CodeFile                     = 'smscon_code'
ConfigFile                   = 'smscon_config'
BootFile                     = 'smscon_boot'

BootCode                     = 'description "smscon %s - nokia n900 remote control utility"\n' % VERSION + \
"""
start on started hildon-desktop
stop on starting shutdown

console none

script
    while [ ! -e /opt/smscon ]; do
        sleep 3
    done
    exec %ssmscon -start > /tmp/smscon_boot.log 2>&1
end script
""" % Path

##############################################################

TIME                         = True

LogPath                      = '/tmp/'
LogFile                      = 'smscon.log'


if TIME:
    logging.basicConfig(filename = (LogPath + LogFile),
                        level    = logging.DEBUG,
                        format   = 'SMSCON %(levelname)s: %(message)s (%(asctime)s)',
                        datefmt  = '%d-%m-%Y %H:%M:%S')
else:
    logging.basicConfig(filename = (LogPath + LogFile),
                        level    = logging.DEBUG,
                        format   = 'SMSCON %(levelname)s: %(message)s')
    
##############################################################

def StatusSMScon():
    """
    Check if smscon_daemon is active.
    """

    Output = os.popen( 'ps ax | grep -v grep | grep %s' % DaemonFile ).read()

    if Output == '': 
        return False
    else: 
        return True

##############################################################    

def StartSMScon():
    """
    Start smscon_daemon.
    """

    os.system(Path + DaemonFile + ' &')
    logging.info('%s is running' % DaemonFile)

##############################################################

def StopSMScon():
    """
    Kill smscon_daemon.
    """

    Output = os.popen('ps ax | grep -v grep | grep %s' % DaemonFile).read()

    if Output != '':
        Exp = re.compile('(\d+) root')
        PIDdaemon = Exp.search(Output).group(1)

        if PIDdaemon != '': 
            os.system('kill %s' % PIDdaemon)
            logging.info( '%s [PID=%s] is stopped' % (DaemonFile, PIDdaemon) )
            print '%s is stopped.' % DaemonFile
        else: 
            logging.error('%s status unknown' % DaemonFile)
            print 'ERROR: %s status unknown.' % DaemonFile
    else:
        logging.info('%s was not running' % DaemonFile)
        print '%s was not running.' % DaemonFile

##############################################################

def StartDaemon(Mode, Function):
    """
    Start the smscon_daemon.
    """
        
    os.system(Path + DaemonFile + ' %s' % Mode + ' %s' % Function + ' &')
    print '%s started.' % DaemonFile

##############################################################

def KillSSH():
    """
    Kill ssh connection.
    """

    if os.popen('pidof ssh').read().strip('\n') != '':
        os.system('kill $(pidof ssh)')
        print 'Ssh connection stopped.'

##############################################################

def ShowLog():
    """
    Show the logfile.
    """

    if CheckFile(LogPath, LogFile) == True:
        f = open(LogPath + LogFile, 'r')
        Output = f.readlines() 
        if Output == []:
            print '%s is empty.' % LogFile 
        else:
            for Text in Output:
                print Text.strip('\n')   
        f.close()
    else:
        print "%s doesn't excist." % LogFile

##############################################################

def CheckFile(Path, File):
    """
    Check if a file exists.
    """

    try:
        f = open(Path + File, 'r')
        f.close()
    except:
        return False
    else:
        return True

##############################################################

def SetBoot():
    """
    Set start smscon_daemon at device boot.
    """
    
    if CheckFile(BootPath, BootFile) == True:
        print '%s is already active.' % BootFile  
    else:
        print "%s doesn't excist." % BootFile
        f = open(BootPath + BootFile, "w")
        f.writelines(BootCode + '\n')
        f.close()
        print 'New %s created & active.' % BootFile 

##############################################################

def ShowIMSI():
    """
    Show IMSI number from smscon_code file.
    """

    if CheckFile(Path, CodeFile) == True:
        f = open(Path + CodeFile, 'r')
        Output = f.readlines() 
        if Output == []:
            print 'ERROR: %s is empty.' % CodeFile
        else:
            for Text in Output:
                print 'IMSI = %s' % Text.strip('\n')   
        f.close()
    else:
        print "%s doesn't excist." % CodeFile

##############################################################

def Delete(Path, File):
    """
    Delete file.
    """

    if CheckFile(Path, File) == True:
        try:
            os.system( 'rm %s' % (Path + File) )
        except:
            print 'ERROR: %s delete failure.' % File
        else:
            print '%s deleted.' % File
    else:
        print '%s already deleted.' % File

##############################################################

def ShowCommands():
    """
    Show available sms commands.
    """

    SmsCommandsList  = []
    SmsCommandPreFix = 'COM_'

    if CheckFile(Path, ConfigFile) == True:
        f = open(Path + ConfigFile, 'r')
        ConfigLines = f.readlines() 
        if ConfigLines == []:
            print 'ERROR: %s is empty.' % ConfigFile
        else:
            try:
                for Line in ConfigLines:
                    Line = Line.strip().replace('\r', '').replace('\n', '')
                        
                    # detect sms command in text line
                    if Line.startswith(SmsCommandPreFix):
                        Data = Line.split('=')
                        Variable = Data[0].replace(' ', '')
                        Value    = Data[1].lstrip(' ')
                        if Value.startswith("'") and Value.endswith("'"):
                            SmsCommandsList.append( (Variable, Value) )
                        else:
                            print 'ERROR: syntax error in user settings (%s).' % Line

                for SmsCommand in SmsCommandsList:
                    print '%s = %s' % (SmsCommand[0], SmsCommand[1])
            except:
                print 'ERROR: error reading user settings.'
        f.close()

    else:
        print "ERROR: %s doesn't excist." % ConfigFile

##############################################################

def InitConfig():
    """
    Check if smscon_config exists, else create new default one.
    """

    ConfigTemplate = '# smscon user settings (v%s)\n' % VERSION + \
"""# (DO NOT edit the encrypted user settings below, use SMSCON-editor!)

# SMS number
SENDERNUMBER      = '+XXXXXXXXXXX'

# SMS commands
COM_CHECK         = 'Check'
COM_REBOOT        = 'Reboot'
COM_POWEROFF      = 'Poweroff'
COM_POWER         = 'Power'
COM_LOCATION      = 'Location'
COM_REMOTEON      = 'Remoteon'
COM_REMOTEOFF     = 'Remoteoff'
COM_CAMERA        = 'Camera'
COM_CALL          = 'Call'
COM_LOCK          = 'Lock'
COM_UNLOCK        = 'Unlock'
COM_TRACKON       = 'Trackon'
COM_TRACKOFF      = 'Trackoff'

# Email settings
EMAILADDRESS      = 'XXXXX@XXXXXXXXXXX.XX'
USER              = 'CTf6qr+x76lU13erkRFHoQ=='
PASSWORD          = 'CTf6qr+x76lU13erkRFHoQ=='
EMAILFROM         = 'XXXXXXXX@XXXXXX.XX'
MAILSERVER        = 'XXXX.XXXXXXXX.XX'
MAILPORT          = 25

# Reverse-ssh settings
REMOTEHOST        = 'XXX.XXXXXXXX.XX'
REMOTEPORT        = 22
REMOTEUSER        = 'CTf6qr+x76lU13erkRFHoQ=='
REMOTEPASSWORD    = 'CTf6qr+x76lU13erkRFHoQ=='

# Send acknowledge SMS
# (send acknowledge SMS after receiving valid sms command: 'yes' / 'no')
COMMANDREPLY      = 'yes'

# Detect keyboard use
# (send acknowledge SMS if keyboard is slided: 'yes' / 'no')
KEYBOARDDETECT    = 'yes'

# Device lock
# (lock device after receiving valid SMS command: 'yes' / 'no')
AUTODEVICELOCK    = 'yes'

# GPS setings
# (if no GPS coordinates after 600 seconds then stop)
GPSTIMEOUT        = 600
# (number of GPS coordinates to acquire and use the most accurate in "Location"-mode)
GPSPOLLING        = 2
# (time between sending GPS coordinate SMS in "Trackon"-mode: 10 / 20 / 30 / 60 / 120)
GPSINTERVAL       = 60
# (method to send GPS coordinates: 'email' / 'sms' / 'both')
GPSSEND           = 'email'
"""

    if CheckFile(Path, ConfigFile) == True:
        return True
    else:
        print 'Creating new user config file in "%s%s".' % (Path, ConfigFile)
        f = open(Path + ConfigFile, 'w')
        f.writelines(ConfigTemplate)
        f.close()
        print 'WARNING: first edit %s before using smscon!' % ConfigFile
        return False

##############################################################

def ShowConfigFile():
    """
    Show smscon_config.
    """

    if CheckFile(Path, ConfigFile) == True:
        os.system('cat %s' % (Path + ConfigFile) )
    else:
        print 'ERROR: %s not found' % ConfigFile

##############################################################
            
def ShowOptions():
    """
    Show options for smscon.
    """

    print '== smscon v%s - Nokia N900 remote control utility ==' % VERSION
    print ' Options:'
    print '  -start      : start %s' % DaemonFile
    print '  -stop       : stop %s' % DaemonFile
    print '  -status     : get %s status' % DaemonFile
    print '  -log        : show log file'
    print '  -del log    : erase log file'
    print '  -sms        : show sms commands'
    print '  -config     : show %s file' % ConfigFile
    print '  -boot       : start %s at device boot' % DaemonFile
    print '  -unboot     : remove start of %s at device boot' % DaemonFile
    print '  -help       : this help menu'
    print ' Special options (normally not needed!):'
    print '  -reset      : factory default' 
    print '  -imsi       : show imsi code file'
    print '  -del imsi   : delete %s file' % CodeFile
    print '  -init       : create default %s file' % ConfigFile
    print '  -del config : delete %s file' % ConfigFile

##############################################################
#    Main
##############################################################

Delay = 0.5

if sys.argv[1:] != []: # 1 or more args given
    NumOfArg = len(sys.argv[1:])

    if NumOfArg == 1: # 1 arg given
        Mode = sys.argv[1] 

        if Mode == '-init':
            if CheckFile(Path, ConfigFile) == False:
                InitConfig()
            else:
                print '%s already created.' % ConfigFile

        elif Mode == '-start':
            if CheckFile(Path, ConfigFile) == True:
                if StatusSMScon() == True:
                    print '%s already active.' % DaemonFile
                else:
                    StartSMScon()
                    time.sleep(Delay)
                    if StatusSMScon() == True:
                        print '%s started.' % DaemonFile
                    else:
                        print 'ERROR: %s failed to start.' % DaemonFile
                        sys.exit(1)
            else:
                print 'ERROR: no %s file present' % ConfigFile
                sys.exit(1)

        elif Mode == '-stop':
            StopSMScon()
            KillSSH()

        elif Mode == '-reset':
            if StatusSMScon() == True:
                StopSMScon()
            else:
                print '%s already stopped.' % DaemonFile
            time.sleep(Delay)
            Delete(LogPath, LogFile)
            time.sleep(Delay)
            Delete(BootPath, BootFile)
            time.sleep(Delay)
            Delete(Path, CodeFile)
            time.sleep(Delay)
            Delete(Path, ConfigFile)
            time.sleep(Delay)            
            KillSSH()

        elif Mode == '-boot':
            SetBoot()

        elif Mode == '-unboot':
            Delete(BootPath, BootFile)                    

        elif Mode == '-status':
            if StatusSMScon() == True:
                print '%s is running.' % DaemonFile
            else:
                print '%s off.' % DaemonFile
    
        elif Mode == '-log':
            ShowLog()

        elif Mode == '-imsi':
            ShowIMSI()

        elif Mode == '-sms':
            ShowCommands()

        elif Mode == '-config':
            ShowConfigFile()

        elif Mode == '-help':
            ShowOptions() 

        else:
            print 'Unknown option (%s).' % Mode
            
    elif NumOfArg == 2: # 2 args given
        Mode = sys.argv[1]
        Func = sys.argv[2]

        if Mode == '-test' or Mode == '-test2':
            if StatusSMScon() == True:
                StopSMScon()
                print '%s stopped.' % DaemonFile
                time.sleep(Delay)
                Delete(LogPath, LogFile)
                time.sleep(Delay)
                StartDaemon(Mode, Func)
                time.sleep(Delay)
                if StatusSMScon() == False:
                    print 'ERROR: %s failed to start.' % DaemonFile
                    sys.exit(1)
                else:
                    logging.info( '"%s" TEST: %s active' % (Func.upper(), DaemonFile) )
            else:
                StartDaemon(Mode, Func)
                time.sleep(Delay)
                if StatusSMScon() == False:
                    print 'ERROR: %s failed to start.' % DaemonFile
                    sys.exit(1)
                else:
                    logging.info( '"%s" TEST: %s active' % (Func.upper(), DaemonFile) )

        elif Mode == '-del':
            if Func == 'log':
                Delete(LogPath, LogFile)
                
            elif Func == 'imsi':
                Delete(Path, CodeFile)

            elif Func == 'config':
                Delete(Path, ConfigFile)

            else:
                print 'Unknown option (%s).' % Func
        else:
            print 'Option error.'

    else: # 3 or more args given
        print 'Option error.'

else: # no arg given
    ShowOptions()  
    sys.exit(1)

