#!/usr/bin/env python

##############################################################
#    smscon_daemon - remote control daemon                   #
##############################################################

VERSION = '0.4.4-5'

import os
import sys
import time
import string
import dbus
import logging
import location
import gobject
import re
import pexpect
import smtplib
import socket
import fileinput
import urllib
import random
from operator import itemgetter 
from subprocess import *
from dbus.mainloop.glib import DBusGMainLoop
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
from email.MIMEMultipart import MIMEMultipart

############################################################################################################################
#    variables
############################################################################################################################

TIME                         = False                             # if set, show time in smscon_log file

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

Path                         = '/usr/bin/'                       # main path of files
BootPath                     = '/etc/event.d/'                   # upstart directory

CodeFile                     = 'smscon_code'                     # code file name
BootFile                     = 'smscon_boot'                     # name of upstart file
ConfigFile                   = 'smscon_config'                   # name of config file
DaemonFile                   = 'smscon_daemon'                   # name of daemon file

LocalHost                    = 'localhost'                       # nokia N900 local address for reverse-ssh 
LocalPort                    = 8080                              # nokia N900 local port for reverse-ssh

TimeOut                      = 5                                 # timeout in seconds
PingMax                      = 3                                 # number of ping commands for connection status check
PhotoName                    = 'frontcam.jpg'                    # frontcam filename
MapName                      = 'gpsmap.png'                      # googlemaps filename

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

Gps                          = 0
GpsList                      = []
GpsActive                    = False
StartTime                    = 0
EndTime                      = 0

SenderNumber                 = ''
EnableKeyboardDetect         = False

#InitialConnectBehaviour      = None
InitialConnectionType        = None 
InitialConnectionIAP         = None
InitialConnectionName        = None

SMSCONactive                 = False

ConfigVars                   = ['SENDERNUMBER',                 
                                'EMAILADDRESS',
                                'COM_CHECK',
                                'COM_REBOOT',
                                'COM_POWEROFF',
                                'COM_POWER',
                                'COM_LOCATION',
                                'COM_REMOTEON',
                                'COM_REMOTEOFF',
                                'COM_CAMERA',
                                'COM_CALL',
                                'COM_LOCK', 
                                'COM_UNLOCK',
                                'COM_TRACKON',
                                'COM_TRACKOFF',
                                'USER',         
                                'PASSWORD',        
                                'EMAILFROM',       
                                'MAILSERVER',      
                                'MAILPORT',
                                'SMTPAUTH',
                                'REMOTEHOST',            
                                'REMOTEPORT',           
                                'REMOTEUSER',       
                                'REMOTEPASSWORD',
                                'COMMANDREPLY',
                                'KEYBOARDDETECT',
                                'AUTODEVICELOCK',
                                'GPSTIMEOUT',
                                'GPSPOLLING',
                                'GPSINTERVAL',
                                'GPSSEND']

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

LogPath                      = '/tmp/'                           # path of log file
LogFile                      = 'smscon.log'                      # log file name

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

############################################################################################################################
#    time
############################################################################################################################

def GetTime():
    """
    Convert time to readable format.
    """

    t = time.localtime( time.time() )

    if t[2] <= 9:
        t2 = '0' + str(t[2])
    else:
        t2 = t[2]

    if t[1] <= 9:
        t1 = '0' + str(t[1])
    else:
        t1 = t[1]

    if t[0] <= 9:
        t0 = '0' + str(t[0])
    else:
        t0 = t[0]

    if t[3] <= 9:
        t3 = '0' + str(t[3])
    else:
        t3 = t[3]

    if t[4] <= 9:
        t4 = '0' + str(t[4])
    else:
        t4 = t[4]

    if t[5] <= 9:
        t5 = '0' + str(t[5])
    else:
        t5 = t[5]
    
    return "%s:%s:%s %s/%s/%s" % (t3, t4, t5, t2, t1, t0)

############################################################################################################################
#    SMS
############################################################################################################################

def OctifyMessage(str):
    """    
    Returns a list of octet bytes representing each char of the input str.               
    """                                       

    bytes    = map(ord, str)
    BitsCons = 0     
    RefBit   = 7     
    Octets   = []          

    while len(bytes):
        Byte = bytes.pop(0)
        Byte = Byte >> BitsCons
                                   
        try:                       
            NextByte = bytes[0]
            BitsToCopy = (NextByte & (0xff >> RefBit)) << RefBit
            Octet = (Byte | BitsToCopy)                                     
        except:
            Octet = (Byte | 0x00)

        if BitsCons != 7:
            Octets.append(Byte | BitsToCopy)
            BitsCons += 1               
            RefBit   -= 1               
        else:                                   
            BitsCons = 0                
            RefBit   = 7                

    return Octets

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

def CreatePDUmessage(Number, Message):
    """                       
    Return list of bytes to represent a valid PDU message.
    """                                                     

    # problem to solve: only works without country code!
    Number = Number.replace('+31', '0') 

    # if number has odd length, add trailing 'F'
    if (len(Number) % 2) == 1:                                
        Number += 'F'                           

    NumberLength = len(Number)

    OctifiedNumber  = [ SemiOctify(Number[i:i+2]) for i in range(0, NumberLength, 2) ]
    OctifiedMessage = OctifyMessage(Message)                                                      

    Header        = 1                  # Header 1
    FirstOctet    = 10                 # First octet of this SMS-DELIVER message (10 dec) (A hex)
                                       # TP-MR (not used)
    TypeOfAddress = 129                # Type of addres of sender number (129 dec) (81 hex)          
    MessageLength = len(Message)       # Length of message                                                        

    PDUmessage = [Header,
                  FirstOctet,
                  NumberLength,
                  TypeOfAddress]       # Header
                                       # First octet of the SMS-SUBMIT message
                                       # Length of number
                                       # Type of address 
    
    PDUmessage.extend(OctifiedNumber)  # Number in semi-octets                                           
    PDUmessage.append(0)               # TP-PID                                  
    PDUmessage.append(0)               # TP-DCS
                                       # TP-VP (not used)
    PDUmessage.append(MessageLength)   # TP-User-Data-Length (length of message)                                              
    PDUmessage.extend(OctifiedMessage) # TP-User-Data (message)

    return PDUmessage                                                             

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

def SemiOctify(str):
    """          
    Expects a string containing two digits, then returns an octet;                     
    first nibble in the octect is the first digit and
    the second nibble represents the second digit.                      
    """                                    

    try:                                   
        D1 = int(str[0])          
        D2 = int(str[1])          
        Octet = (D2 << 4) | D1
    except:                                 
        Octet = (1 << 4) | D1      

    return Octet

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

def DeOctifyMessage(Array):
    """
    Deoctify received message and return text string.
    """
    
    RefBit   = 1
    Doctect  = []    
    ByteNext = 0x00    

    for i in Array:
        ByteCurrent = ((i & (0xff >> RefBit)) << RefBit) >> 1
        ByteCurrent |= ByteNext                                      

        if RefBit != 7:
            Doctect.append(ByteCurrent)
            ByteNext = (i & (0xff << (8 - RefBit)) ) >> 8 - RefBit
            RefBit += 1
            
        else:                                                                  
            Doctect.append(ByteCurrent)                                        
            ByteNext = (i & (0xff << (8 - RefBit)) ) >> 8 - RefBit
            Doctect.append(ByteNext)                                        
            ByteNext = 0x00                                                   
            RefBit = 1                                               

    return ''.join([chr(i) for i in Doctect])

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

def SMSreceive(PDUmessage, MessageCenter, SomeString, Number):
    """
    Receive SMS command and execute command.
    """

    global SenderNumber
    SenderNumber = Number 

    MessageLength = int(PDUmessage[18])
    MessageArray  = PDUmessage[19:len(PDUmessage)]

    Message = DeOctifyMessage(MessageArray) # decode sms message as plain text

    ProcessCommand(Message, SenderNumber) # process sms command

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

def SMSsend(Number, Message):
    """
    Send reply SMS to sender number.
    """

##    Dbus way of SMS sending:
##
##    bus = dbus.SystemBus()
##    smsobject = bus.get_object('com.nokia.phone.SMS',
##                               '/com/nokia/phone/SMS/ba212ae1')
##    smsiface = dbus.Interface(smsobject,
##                              'com.nokia.csd.SMS.Outgoing')
##
##    arr = dbus.Array( CreatePDUmessage(Number, Message) )
##    msg = dbus.Array([arr])
##
##    smsiface.Send(msg, '')

    MessageLength = len(Message)
    
    if MessageLength > 160:
        logging.error( 'failed to send SMS message to "%s" (length = %s chars.)' % (Number, MessageLength) )          
    else:
        try:
            Delay = 0.5
            gsm = pexpect.spawn('pnatd') # open 'pnatd'
            gsm.send('AT\r') # test is gsm modem is available
            time.sleep(Delay)
            gsm.send('AT+CMGF=1\r') # set gsm modem to sms text
            time.sleep(Delay)
            gsm.send( 'AT+CMGS="%s"\r' % Number ) # set sms number
            gsm.send( '%s' % Message + chr(26) ) # set sms message & send
            time.sleep(Delay)
            gsm.sendeof()
        except:
            logging.error('failed to send SMS message to "%s" (send error)' % Number)        
        else:
            time.sleep(3)

############################################################################################################################
#    email
############################################################################################################################

def EMAILsend(EmailTo, Subject, Text, Attachment=None):
    """
    Send email to owner of the device.
    """

    RandomNumber = random.randint(1, 100000)
    
    HtmlTextPage = \
""" 
<html> 
<head></head> 
<body> 
<p>
%s<br>
</p>
</body> 
</html>
""" % Text

    HtmlImagePage = \
""" 
<html> 
<head></head> 
<body> 
<p>
%s<br>
""" % Text + \
'<img src="cid:map%s" alt="map of location of Nokia N900" /><br>' % RandomNumber + \
"""
</p>
</body> 
</html>
"""

    Message            = MIMEMultipart('related') 
    Message['Subject'] = Subject
    Message['From']    = 'NokiaN900'
    Message['To']      = EmailTo

    # html text only
    if Attachment == None: 
        Message.attach( MIMEText(HtmlTextPage, 'html') )

    # html text & image provided  
    else: 
        Message.attach( MIMEText(HtmlImagePage, 'html') )

        try:
            File = open(Attachment, 'rb')
            Image = MIMEImage( File.read() )
            File.close()
        except:
            logging.error('EMAIL: attachment not found')
            return
        else:
            Image.add_header('Content-ID', '<map%s>' % RandomNumber)
            Message.attach(Image)

    try:
        # connect to mail server
        server = smtplib.SMTP(MAILSERVER, MAILPORT)
    except (socket.error, smtplib.SMTPConnectError):
        server.quit()
        logging.error('EMAIL: mailserver connect failure')
        return

    # identify
    server.ehlo()
        
    # if smtp server requires secure authentication
    if server.has_extn('STARTTLS'):
        server.starttls()
        server.ehlo()

    try:
        # set username & paswword
        server.login(USER, PASSWORD)
    except smtplib.SMTPAuthenticationError:
        server.quit()
        logging.error('EMAIL: wrong username/password')
        return
    
    try:
        # send email
        server.sendmail( EMAILFROM,
                         EmailTo,
                         Message.as_string() )
    except smtplib.SMTPException, e:
        logging.error('EMAIL: [%s]' % e)
    else:
        logging.info('send email message to "%s"' % EmailTo)
    finally:
        server.quit()

############################################################################################################################
#   save new number
############################################################################################################################

def SaveNumber(SenderNumber):
    """
    Save new SenderNumber as SENDERNUMBER in "smscon_config" file.
    """ 

    global SENDERNUMBER

    # update SENDERNUMBER
    SENDERNUMBER = SenderNumber

    UserVar = 'SENDERNUMBER'
    File    = '%s' % (Path + ConfigFile)

    try:
        for Line in fileinput.FileInput(File, inplace = True):
            if Line.startswith(UserVar):
                Line = "%s      = '%s'" % (UserVar, SenderNumber)
            print Line.rstrip()
    except:
        logging.error("couldn't save new SMS number (%s)" % SenderNumber)
    else:
        logging.info( 'new SMS number (%s) saved in %s' % (SenderNumber, ConfigFile) )

############################################################################################################################
#    command processing
############################################################################################################################

def ProcessCommand(Command, SenderNumber):
    """
    Process the received message.
    """

    CommandList = [COM_CHECK,
                   COM_REBOOT,
                   COM_POWEROFF,
                   COM_POWER,
                   COM_LOCATION,
                   COM_REMOTEON,
                   COM_REMOTEOFF,
                   COM_CAMERA,
                   COM_CALL,
                   COM_LOCK, 
                   COM_UNLOCK,
                   COM_TRACKON,
                   COM_TRACKOFF]

    # Check if SMS message has an SMSCON command
    if Command in CommandList:
              
        # SMSCON is set active
        SMSCONactive = True
   
        logging.info( 'received SMSCON command [%s] from "%s"' % (Command, SenderNumber) )

        # if new SenderNumber is different from stored SENDERNUMBER in "smscon_config" file, store new SenderNumber in "smscon_config" file.
        if SenderNumber != SENDERNUMBER:
            SaveNumber(SenderNumber)

        # auto device locking
        if AUTODEVICELOCK == 'yes' and Command != COM_UNLOCK:
            EnableDeviceLock(False)
        elif AUTODEVICELOCK == 'no' and Command != COM_LOCK:
            DisableDeviceLock(False)

        # command reply
        if COMMANDREPLY == 'yes':
            Reply = 'NOKIA N900\n' + \
                    '%s\n' % GetTime() + \
                    '-reply-\n' + \
                    'command (%s) accepted.\n' % Command
            
            if AUTODEVICELOCK == 'yes' and Command != COM_UNLOCK:
                SMSsend(SenderNumber,
                        Reply + \
                        '-security-\n' + \
                        'phone is locked.\n')
            else:
                SMSsend(SenderNumber, Reply)

        # keyboard detection
        global EnableKeyboardDetect
        if KEYBOARDDETECT == 'yes':
            EnableKeyboardDetect = True
        elif KEYBOARDDETECT == 'no':
            EnableKeyboardDetect = False      

        # command execution
        if Command == COM_CHECK:
            ShowSMScommands('sms')

        elif Command == COM_REBOOT:
            EnableReboot()

        elif Command == COM_POWEROFF:
            EnablePoweroff()            

        elif Command == COM_POWER:
            EnablePowerStatus()

        elif Command == COM_LOCATION:
            StoreCurrentNetwork() # save current data network
            EnableConnection('GPRS') # enable GPRS data network
            #EnableConnectBehaviour('GPRS') # set "Internet connection" behaviour
            EnableGPStracking('single')

        elif Command == COM_REMOTEON:
            StoreCurrentNetwork() # save current data network
            EnableConnection('GPRS') # enable GPRS data network
            #EnableConnectBehaviour('GPRS') # set "Internet connection" behaviour
            EnableSSHcontrol()

        elif Command == COM_REMOTEOFF:
            DisableSSHcontrol()
            RestorePreviousNetwork() # re-enable stored data network

        elif Command == COM_CAMERA:
            StoreCurrentNetwork() # save current data network
            EnableConnection('GPRS') # enable GPRS data network
            #EnableConnectBehaviour('GPRS') # set "Internet connection" behaviour
            EnableCamera()
            RestorePreviousNetwork() # re-enable stored data network

        elif Command == COM_CALL:
            EnablePhonecall()

        elif Command == COM_LOCK:
            EnableDeviceLock(True)

        elif Command == COM_UNLOCK:
            DisableDeviceLock(True)

        elif Command == COM_TRACKON:
            StoreCurrentNetwork() # save current data network
            EnableConnection('GPRS') # enable GPRS data network
            #EnableConnectBehaviour('GPRS') # set "Internet connection" behaviour
            EnableGPStracking('multi')

        elif Command == COM_TRACKOFF:
            DisableGPStracking()
            RestorePreviousNetwork() # re-enable stored data network

############################################################################################################################
#   show SMS commands
############################################################################################################################

def ShowSMScommands(Type):
    """
    Log or SMS list of SMS commands.
    """

    ConfigVars = []
    Prefix     = 'COM_'
    MaxChars   = 160  

    # get specific variables
    for Var in globals():
        if Var.startswith(Prefix):
            ConfigVars.append(Var)

    # sort the list
    ConfigVars.sort()

    # create log entry
    if Type == 'log':
        for UserVar in ConfigVars:
            Value = eval(UserVar)
            logging.info( '%s = [%s]' % (UserVar, Value) )

    # create (multiple) SMS messages
    elif Type == 'sms':

        NumConfigVars = len(ConfigVars)

        n = 1
        Text = 'NOKIA N900\n' + \
               '%s\n' % GetTime() + \
               '-check #%s-\n' % n

        i = 0
        while i < len(ConfigVars):
            Name    = ConfigVars[i].replace('COM_', '')
            Value   = eval(ConfigVars[i])
            AddText = "%s = '%s'\n" % (Name, Value)
            Chars   = len(Text) + len(AddText)
          
            if Chars <= MaxChars:
                Text += AddText

                if i == len(ConfigVars) - 1:
                    SMSsend(SenderNumber, Text)    
                    logging.info('send SMS message with SMSCON commands to "%s"' % SenderNumber)

            elif Chars > MaxChars:
                SMSsend(SenderNumber, Text)
                logging.info('send SMS message with SMSCON commands to "%s"' % SenderNumber)

                n += 1
                Text = 'NOKIA N900\n' + \
                       '%s\n' % GetTime() + \
                       '-check #%s-\n' % n
                i -= 1
                
            i += 1

############################################################################################################################
#   device lock
############################################################################################################################

def EnableDeviceLock(SendReply=False):
    """
    Lock device after receiving valid sms command.
    """

    os.system ('dbus-send --system --type=method_call \
               --dest=com.nokia.system_ui \
               /com/nokia/system_ui/request \
               com.nokia.system_ui.request.devlock_open \
               string:"com.nokia.mce" \
               string:"/com/nokia/mce/request" \
               string:"com.nokia.mce.request" \
               string:"devlock_callback" uint32:"3"')

    logging.info('Nokia phone is locked')

    if SendReply:
        SMSsend(SenderNumber,
                'NOKIA N900\n' + \
                '%s\n' % GetTime() + \
                '-lock-\n' + \
                'phone has been locked.')

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

def DisableDeviceLock(SendReply=False):
    """
    Unlock device.
    """

    os.system ('dbus-send --system --type=method_call \
               --dest=com.nokia.system_ui \
               /com/nokia/system_ui/request \
               com.nokia.system_ui.request.devlock_close \
               string:"com.nokia.mce" \
               string:"/com/nokia/mce/request" \
               string:"com.nokia.mce.request" \
               string:"devlock_callback" \
               uint32:"0"')

    logging.info('Nokia phone is unlocked')

    if SendReply:
        SMSsend(SenderNumber,
                'NOKIA N900\n' + \
                '%s\n' % GetTime() + \
                '-unlock-\n' + \
                'phone has been unlocked.')

############################################################################################################################
#   system
############################################################################################################################

def EnableReboot():
    """
    Reboot the device.
    """

    logging.info('executing command "%s"' % Com)
    
    time.sleep(10)
    os.system('reboot')
    
    ExitDaemon()

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

def EnablePoweroff():
    """
    Shutdown device.
    """

    logging.info('executing command "%s"' % Com)
    
    time.sleep(10)
    os.system('poweroff')
    
    ExitDaemon()

############################################################################################################################
#   camera
############################################################################################################################

def EnableCamera():
    """
    Get picture of front camera and send it to email address.
    """

    if TakeCamPicture() == True:
        EMAILsend(EMAILADDRESS,
                  '%s command / Nokia N900' % COM_CAMERA,
                  'This is a frontcam picture from the Nokia N900 device:',
                  LogPath + PhotoName)
        logging.info('camera picture send to "%s"' % EMAILADDRESS)

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

def TakeCamPicture():
    """
    Acquire front camera picture.
    """

    Delay = 5

    CamName     = 'video1'
    CamRes      = (640,480)
    CamEncoding = 'jpegenc'

    try:
        os.popen('gst-launch v4l2camsrc device=/dev/%s num-buffers=1 ! video/x-raw-yuv,width=%s,height=%s ! ffmpegcolorspace ! %s ! filesink location=%s' \
                 % (CamName,
                    CamRes[0],
                    CamRes[1],
                    CamEncoding,
                    LogPath + PhotoName) )
    except:
        logging.error('camera picture failed (capture error)')
        return False
    else:
        time.sleep(Delay)

        if os.path.isfile(LogPath + PhotoName) == True:
            logging.info('camera picture acquired')
            return True
        else:
            logging.error('camera picture failed (file not found)')
            return False

############################################################################################################################
#    phone call
############################################################################################################################

def EnablePhonecall():
    """
    Make phone call to sender number.
    """

    try:
        os.system('run-standalone.sh dbus-send --system --dest=com.nokia.csd.Call \
                   --type=method_call /com/nokia/csd/call com.nokia.csd.Call.CreateWith \
                   string:"%s" \
                   uint32:0' % SENDERNUMBER )
        
        logging.info('making phonecall to "%s"' % SenderNumber)          
    except:
        logging.error('failed to make phonecall to "%s"' % SenderNumber)

############################################################################################################################
#    data connection
############################################################################################################################

def StatusConnection(Log=False): 
    """
    Get info of current data connection; type and status
    """

    Wlan = os.popen('ifconfig | grep "wlan0"').read()
    Gprs = os.popen('ifconfig | grep "gprs0"').read() 

    # wlan data connection active
    if Wlan != '' and Gprs == '':
        Type = 'WLAN'
        if Log == True:
            logging.info('current network is "%s"' % Type)

        return Type

    # gprs data connection active
    elif Wlan == '' and Gprs != '':
        Type = 'GPRS'
        if Log == True:
            logging.info('current network is "%s"' % Type)

        return Type
    
    # no data connection active
    else:
        return 'NONE' 

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

def EnableConnection(NewType):
    """
    Connect to specific data connection ('WLAN' / 'GPRS').
    """

    Delay = 5

    CurrentType = StatusConnection(False)

    # not connected to a data connection
    if CurrentType == 'NONE':
        pass

    # already connected to a data connection
    elif (CurrentType == 'WLAN' and NewType == 'GPRS') or (CurrentType == 'GPRS' and NewType == 'WLAN'):

        # disconnect current data connection before connecting to new type data connection
        DisableConnection(CurrentType) 
        
    # already connected to same type data connection
    elif (CurrentType == 'WLAN' and NewType == 'WLAN') or (CurrentType == 'GPRS' and NewType == 'GPRS'):
        
        logging.info('network (%s) already connected' % CurrentType)
        return True

    if NewType == 'GPRS':
        Type, IAP, Name = GetCurrentGPRSname()
    elif NewType == 'WLAN':
        Type, IAP, Name = GetCurrentLANname()
    elif NewType == 'NONE':
        Type, IAP, Name = 'NONE', 'NONE', 'NONE'

    #logging.debug( '[%s, %s, %s]' % (Type, IAP, Name) )

    if IAP == 'NONE':
        logging.error('no available network found')
        return False
    else:
        # initiate new data connection
        os.system( 'dbus-send --system --type=method_call --dest=com.nokia.icd /com/nokia/icd com.nokia.icd.connect string:"%s" uint32:0' % IAP )
        time.sleep(Delay)

        # check new connection is working
        NewType = StatusConnection(False)
        
        if NewType == 'WLAN' or NewType == 'GPRS':
            logging.info( 'new network (%s: %s) connection successfull' % (NewType, Name) )
            return True

        elif NewType == 'NONE':
            logging.error( 'failed to connect to %s: "%s" (could not connect)' % (NewType, Name) )
            return False

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

def DisableConnection(CurrentType): 
    """
    Disconnect any current WIFI/GPRS dataconnection.
    """

    Delay = 3

    # disconnect data network
    os.system('dbus-send --system --dest=com.nokia.icd2 /com/nokia/icd2 com.nokia.icd2.disconnect_req uint32:0x8000')
    logging.info('current network (%s) disconnected' % CurrentType)

    time.sleep(Delay)

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

def GetCurrentGPRSname(): 
    """
    Get name of GPRS data connection from current inserted SIM card in Nokia device.
    """

    NetworkList = GetAvailableNetworks()

    for Network in NetworkList:
        Type = Network[0]
        IAP  = Network[1]
        Name = Network[2]
        
        if Type == 'GPRS': # format: (Type, IAP, Name, Imsi)
            Imsi = Network[3]
            if Imsi == GetCode('IMSI'):
                #logging.debug('[%s]' % IAP)
                return Type, IAP.replace('@32@', ' '), Name

    return 'NONE', 'NONE', 'NONE'

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

def GetCurrentLANname():
    """
    Get name of active WLAN data connection.
    """

    NetworkList = GetAvailableNetworks()

    # get last used data network IAP
    LastUsedNetwork = os.popen(' gconftool -g /system/osso/connectivity/IAP/last_used_network').read().strip('\n')
    #logging.debug('LastUsedNetwork = [%s]' % LastUsedNetwork)

    for Network in NetworkList:
        Type = Network[0]
        IAP  = Network[1]
        Name = Network[2]
        
        if Type == 'WLAN': # format: (Type, IAP, Name)
            if LastUsedNetwork == IAP:
                #logging.debug('WLAN: %s' % Name)
                return Type, IAP, Name

    return 'NONE', 'NONE', 'NONE'
    
###############################

def GetAvailableNetworks():
    """
    Get list of all available data connections (stored under "Internet connections" in menu).
    """

    Output = os.popen('gconftool -R /system/osso/connectivity/IAP | grep IAP').read()
    E = re.compile('/system/osso/connectivity/IAP/(\S+):')
    IAPlist = E.findall(Output) 

    NetworkList = []

    for IAP in IAPlist:
        Type = os.popen('gconftool -g /system/osso/connectivity/IAP/%s/type' % IAP).read().replace('_INFRA', '').strip('\n')
        if Type == 'GPRS':
            Name = os.popen('gconftool -g /system/osso/connectivity/IAP/%s/name' % IAP).read().strip('\n')
            Imsi = os.popen('gconftool -g /system/osso/connectivity/IAP/%s/sim_imsi' % IAP).read().strip('\n')
            NetworkList.append( (Type, IAP, Name, Imsi) )
        elif Type == 'WLAN':
            Name = os.popen('gconftool -g /system/osso/connectivity/IAP/%s/name' % IAP).read().strip('\n')
            NetworkList.append( (Type, IAP, Name) )

    #logging.debug('[%s]' % NetworkList)

    return NetworkList # = [ (Type, IAP, Name, Imsi), (Type, IAP, Name), etc.]

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

def EnableConnectBehaviour(Mode):
    """
    Set Nokia phone data connection behavior.
    """    

    Type = StatusConnectBehaviour()
    if Type != Mode: # if new behaviour is different from current

        # store current "Internet connection" behavior
        global InitialConnectBehaviour
        InitialConnectBehaviour = Type
        
        SetConnectBehaviour(Mode)

        # check new behaviour setting
        Type = StatusConnectBehaviour()
        if Type == Mode:
            logging.info('internet connection behaviour set to "%s"' % Mode)
        else:
            logging.error('failed to set internet connection behaviour (%s)' % Type)
    else:
        logging.info('internet connection behaviour already set to "%s"' % Mode)

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

def StatusConnectBehaviour():
    """
    Get Nokia phone data connection behaviour.
    """ 

    Mode = os.popen('gconftool-2 -g --list-type string /system/osso/connectivity/network_type/auto_connect').read().strip('\n') 

    if Mode == '[]':
        return 'ASK'
    elif Mode == '[*]':
        return 'ANY'
    elif Mode == '[GPRS]':
        return 'GPRS'    
    elif Mode == '[WLAN_INFRA]':
        return 'WLAN'

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

def SetConnectBehaviour(Mode):
    """
    Set Nokia device data connection behaviour.
    """

    Delay = 2

    # options: [WLAN_INFRA], [GPRS], [*] <=='any', [] <=='ask'
    if Mode == 'ASK':
        String = ''
    elif Mode == 'WLAN':
        String = 'WLAN_INFRA'
    elif Mode == 'GPRS':        
        String = 'GPRS'
    elif Mode == 'ANY':
        String = '*'

    #logging.debug('Mode = [%s]' % Mode)
        
    # set setting "Connect automatically"
    os.system('gconftool-2 -s --type list --list-type string /system/osso/connectivity/network_type/auto_connect [%s]' % String)

    time.sleep(Delay)

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

def StoreCurrentNetwork():
    """
    Save current active data network.
    """

    global InitialConnectionType
    global InitialConnectionIAP
    global InitialConnectionName

    Type = StatusConnection()
    if Type == 'WLAN':
        InitialConnectionType, InitialConnectionIAP, InitialConnectionName = GetCurrentLANname()
        #logging.debug('InitialConnectionType = %s' % InitialConnectionType)
        #logging.debug('InitialConnectionIAP = %s' % InitialConnectionIAP)
        #logging.debug('InitialConnectionName = %s' % InitialConnectionName)
    elif Type == 'GPRS':
        InitialConnectionType = 'GPRS'
        InitialConnectionName = GetCurrentGPRSname()
    else:
        InitialConnectionType = 'NONE'
        InitialConnectionName = 'NONE'

    logging.info( 'store current network (%s: %s)' % (Type, InitialConnectionName) )

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

def RestorePreviousNetwork():
    """
    Re-enable previous stored data network.
    """

    if InitialConnectionType != None:
        if InitialConnectionType == 'GPRS' or InitialConnectionType == 'WLAN':
            logging.info( 'restoring saved network (%s: %s)' % (InitialConnectionType, InitialConnectionName) )
            EnableConnection(InitialConnectionType)
        else:
            DisableConnection('GPRS')

############################################################################################################################
#    power status
############################################################################################################################

def EnablePowerStatus():
    """
    Get battery charge and send sms reply.
    """

    ChargePerc = dev_obj.GetProperty('battery.charge_level.percentage') # charge amount of battery in percentage

    logging.info('batterycharge = %s %%' % ChargePerc)

    SMSsend(SenderNumber,
            'NOKIA N900\n' + \
            '%s\n' % GetTime() + \
            '-battery-\n' + \
            'charge = %s%%' % ChargePerc )

############################################################################################################################
#    SSH 
############################################################################################################################

def EnableSSHcontrol():
    """
    Start the ssh routine.
    """

    if StatusSSH() == False:
        if StatusRemoteHost() == False:
            logging.error('ssh connection failure to "%s"' % REMOTEHOST)
            return
        else:
            StartSSH()
            return
    else:
        logging.info('ssh connection is already active')
        return

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

def DisableSSHcontrol():
    """
    Stop the ssh routine.
    """

    if StatusSSH() == True:
        logging.info('trying to disable ssh connection to "%s"' % REMOTEHOST)
        StopSSH()
    else:
        logging.info('ssh connection is already disabled')

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

def StatusRemoteHost():
    """
    Check if remote host is available with a ping command and return
    - false; no or bad ping 
    - true;  good ping (remotehost is available)
    """

    if os.WEXITSTATUS( os.system( 'ping -c %s %s >> /dev/null 2>&1' % (PingMax, REMOTEHOST) ) ) == 0:
        return True
    else:
        return False 
        
###############################

def StartSSH():
    """
    Start reverse-ssh connection to remote host.
    """

    logging.info('connecting to "%s"' % REMOTEHOST)


    (Output, ExitStatus) = pexpect.run( 'ssh -n -N -T -f -p %s -R %s:%s:%s %s@%s &' % (REMOTEPORT, LocalPort, LocalHost, REMOTEPORT, REMOTEUSER, REMOTEHOST),
                                        events = { '(?i)(password|passphrase)':REMOTEPASSWORD + '\n', '(?i)(yes/no) ?':'yes' + '\n' },
                                        withexitstatus = True )
    
    #logging.debug( 'output = %s' % Output.strip('\n') )
    #logging.debug('status = %s' % ExitStatus)

    if ExitStatus == 0:
        logging.info('ssh connection to "%s" established' % REMOTEHOST)

        SMSsend(SenderNumber,
                'NOKIA N900\n' + \
                '%s\n' % GetTime() + \
                '-ssh-\n' + \
                'connection established.')
    else:
        logging.error('ssh connection failed to "%s"' % REMOTEHOST)
        if StatusSSH() == True:
            StopSSH()

        SMSsend(SenderNumber,
                'NOKIA N900\n' + \
                '-ssh-\n' +\
                'connection failed.')

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

def StopSSH(Verbose=True):
    """
    Kill reverse-ssh connection to remote host.
    """

    if Verbose == True:
        logging.info('trying to kill ssh')

    PID = os.popen('pidof ssh').read().strip('\n')

    if PID == '':
        if Verbose == True:
            logging.info("ssh wasn't active")
    else:
        os.system('kill $(pidof ssh)')
        if Verbose == True:
            logging.info('ssh is stopped [PID=%s]' % PID)        

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

def StatusSSH():
    """
    Check if ssh is active or not running.
    """

    PID = os.popen('pidof ssh').read().strip('\n')

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

############################################################################################################################
#    GPS
############################################################################################################################

def EnableGPStracking(Mode):
    """
    Start the GPS device mainloop.
    """

    global GpsMode
    GpsMode = Mode
    
    global GpsActive
    if GpsActive == False:
        GpsActive = True

        # enable GPS device control
        gobject.idle_add(GPSstart, GpsControl)
    else:
        logging.warning('GPS device already active')

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

def DisableGPStracking():
    """
    Stop the GPS device mainloop.
    """

    global GpsActive
    if GpsActive == True:
        GpsActive = False

        # stop the GPS device
        GpsData.stop()
        logging.info('stopped acquiering GPS coordinates')
    else:
        logging.info('GPS device already stopped')

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

def GPSstart(GpsData):
    """
    Start the GPS device.
    """
    
    global StartTime
    global GpsState
    GpsState = False

    if GpsMode == 'single':
        logging.info('starting GPS device in location mode')
    elif GpsMode == 'multi':
        logging.info('starting GPS device in tracking mode')
    
    StartTime = time.time()
    GpsData.start()
    
    return False

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

def GPSstop(GpsControl, GpsData):
    """
    Stop the GPS device.
    """

    global GpsActive
    GpsActive = False
    
    logging.info('stopping GPS device')
    GpsData.quit()

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

def GPSchanged(GpsDevice, GpsData):
    """
    Get GPS device data.
    """

    global Gps
    global GpsList
    global GPSPOLLING
    global GpsState
    global StartTime

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

    # check GPS device timout
    PastTime = time.time() - StartTime
    if GpsState == False:
        #logging.debug('StartTime = %s' % StartTime)
        if PastTime >= GPSTIMEOUT:
            logging.error('GPS device timeout after %.1f sec' % PastTime)

            # stop the GPS device
            GpsData.stop()

            if GPSSEND == 'sms':
                SMSsend(SenderNumber,
                        'NOKIA N900\n' + \
                        '-GPS-\n' + \
                        'failure\n' + \
                        'Search time = %.1f sec.' % PastTime)
                logging.info('send GPS timeout failure by %s' % GPSSEND)
                    
            elif GPSSEND == 'email':
                EMAILsend(EMAILADDRESS,
                          'From "%s" command / Nokia N900' % COM_TRACKON,
                          'GPS device timeout after %.1f sec' % PastTime)
                logging.info('send GPS timeout failure by %s' % GPSSEND)
            return
    else:
        # adjust start time of GPS device
        StartTime = time.time()

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

    # GPS device has fix.
    if GpsDevice.fix[1] & location.GPS_DEVICE_LATLONG_SET:
            
        Latitude  = GpsDevice.fix[4]
        Longitude = GpsDevice.fix[5]
        Accuracy  = GpsDevice.fix[6] / 100

        # no valid coordinate acquired by GPS device
        if (str(Latitude) == 'nan') or (str(Longitude) == 'nan') or (str(Accuracy) == 'nan'):
            GpsState = False
            logging.info('waiting for valid GPS coordinate (time = %.1f sec.)'% PastTime)
            return

        # valid coordinate acquired by GPS device
        else:
            GpsState = True
            # single mode
            if GpsMode == 'single':
                if Gps == 0:
                    logging.info('start collecting GPS coordinates')

                # make GPS coordinate list
                GpsList.append( (Latitude,
                                 Longitude,
                                 Accuracy) )
                logging.info( 'GPS coordinate acquired (#%s, %f, %f, %.1f m.)' % (Gps + 1,
                                                                                  Latitude,
                                                                                  Longitude,
                                                                                  Accuracy) )
                Gps += 1
                if Gps == GPSPOLLING:
                    if GPSPOLLING != 1:
                        # sort GPS coordinate list on 'Accuracy'
                        GpsList = sorted( GpsList, key=itemgetter(2) )
                        
                        # get most accurate GPS coordinate
                        LatBest, LongBest, AccBest = GpsList[0]
                        logging.info( 'most accurate GPS coordinate (%f, %f, %.1f m.)' % (LatBest,
                                                                                          LongBest,
                                                                                          AccBest) )
                    else:
                        # get GPS coordinate
                        LatBest, LongBest, AccBest = GpsList[0]
                        logging.info( 'GPS coordinate (%f, %f, %.1f m.)' % (LatBest,
                                                                            LongBest,
                                                                            AccBest) )                       
                    GpsText = 'NOKIA N900\n' + \
                              '-GPS-\n' + \
                              'Lat = %f\n' % LatBest + \
                              'Long = %f\n' % LongBest + \
                              'Pos accuracy = %.1f m.\n' % AccBest + \
                              'Search time = %.1f sec.' % PastTime
                     
                    if GPSSEND == 'sms':
                        SMSsend(SenderNumber, GpsText)
                        logging.info('GPS coordinate send to "%s"' % SenderNumber)

                    elif GPSSEND == 'email':
                        if CreateGoogleMap(LatBest, LongBest): 
                            EMAILsend(EMAILADDRESS,
                                      'From "%s" command / Nokia N900' % COM_LOCATION,
                                      GpsText.replace('\n', '<br>'),
                                      LogPath + MapName)
                            logging.info('GPS coordinate map send to "%s"' % EMAILADDRESS) 
                        else:
                            EMAILsend( EMAILADDRESS,
                                       'From "%s" command / Nokia N900' % COM_LOCATION,
                                       GpsText.replace('\n', '<br>') )
                            logging.info('GPS coordinate send to "%s"' % EMAILADDRESS) 

                    # erase GPS coordinate list
                    GpsList = []
                    # stop the GPS device
                    GpsData.stop()
                    return
                    
            # tracking mode
            elif GpsMode == 'multi':
                logging.info( 'GPS coordinate acquired (%f, %f, %.1f m.)' % (Latitude,
                                                                             Longitude,
                                                                             Accuracy) )
                GpsText = 'NOKIA N900\n' + \
                          '-GPS-\n' + \
                          'Lat = %f\n' % Latitude + \
                          'Long = %f\n' % Longitude + \
                          'Pos accuracy = %.1f m.\n' % Accuracy + \
                          'Search time = %.1f sec.' % PastTime

                if GPSSEND == 'sms':
                    SMSsend(SenderNumber, GpsText)
                    logging.info('GPS coordinate send to "%s"' % SenderNumber)

                elif GPSSEND == 'email':
                    if CreateGoogleMap(Latitude, Longitude): 
                        EMAILsend(EMAILADDRESS,
                                  'From "%s" sms command / Nokia N900' % COM_TRACKON,
                                  GpsText.replace('\n', '<br>'),
                                  LogPath + MapName)
                        logging.info('GPS coordinate map send to "%s"' % EMAILADDRESS)
                    else:
                        EMAILsend( EMAILADDRESS,
                                   'From "%s" sms command / Nokia N900' % COM_TRACKON,
                                   GpsText.replace('\n', '<br>') )
                        logging.info('GPS coordinate send to "%s"' % EMAILADDRESS)
    else:
        logging.info('waiting for GPS device satellite fix')

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

def GPSerror(GpsControl, GpsError, GpsData):
    """
    GPS device error detected.
    """

    global GpsActive
    GpsActive = False

    logging.error('GPS device error (%d)' % GpsError)
    logging.error('stopping failed GPS device')
    GpsData.quit()

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

def CreateGoogleMap(Latitude, Longitude):
    """
    Create map of current GPS coordinate.
    """

    MapZoom     = 16
    MapSize     = (600,600)
    MarkerColor = 'red'
    MarkerLabel = 'N'

    MapUrl = 'http://maps.google.com/maps/api/staticmap?center=%s,%s&zoom=%s&size=%sx%s&format=png&markers=color:%s|label:%s|%s,%s&sensor=false' \
              % (Latitude,
                 Longitude,
                 MapZoom,
                 MapSize[0],
                 MapSize[1],
                 MarkerColor,
                 MarkerLabel,
                 Latitude,
                 Longitude)

    try:
        urllib.urlretrieve(MapUrl, LogPath + MapName)
    except:
        logging.error('failed to create GPS coordinate map (retrieve error)')
        return False
    else:
        if os.path.isfile(LogPath + MapName) == True:
            logging.info('created GPS coordinate map')
            return True
        else:
            logging.error('failed to create GPS coordinate map (file not found)')
            return False

############################################################################################################################
#    SIM card
############################################################################################################################

def ValidateIMSI():
    """
    Check if current used IMSI code from SIM card is authorized.
    """
    
    CurrentIMSI = GetCode('IMSI')

    # no SIM card found
    if CurrentIMSI == None:
        logging.critical('no SIM card present; %s will quit' % DaemonFile)
        quit()

    # compare current IMSI code with saved one in file.
    elif CurrentIMSI == ReadIMSI():
        logging.info('authorized IMSI code found')

    else:
        logging.warning('IMSI code has changed to "%s"' % CurrentIMSI)

        # save new IMSI code to file
        WriteIMSI(CurrentIMSI)    

        # send reply sms
        SMSsend(SenderNumber,
                'NOKIA N900\n' + \
                '%s\n' % GetTime() + \
                '-New SIM card-\n' + \
                'IMSI = %s\n' % CurrentIMSI + \
                'IMEI = %s\n' % GetCode('IMEI') + \
                'Operator = "%s".' % GetOperatorName() )

        logging.info('new SIM number/IMSI code send to "%s"' % SenderNumber)

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

def ReadIMSI():
    """
    Load IMSI code from file.
    """

    if CheckFile(Path, CodeFile) == True:
        f = open(Path + CodeFile, 'r+')
        Code = f.readline().strip('\n')
        f.close()

        logging.info('reading valid IMSI code (%s) from file' % Code)

        return Code
    else:
        logging.warning('initalizing new %s file with current valid IMSI code' % ConfigFile)
    
        CodeValid = GetCode('IMSI')

        # write new file with current valid imsi code
        f = open(Path + CodeFile, 'w')
        f.writelines(CodeValid)
        f.close()

        logging.info('current valid IMSI code (%s) saved to file' % CodeValid)

        return CodeValid

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

def WriteIMSI(Code):
    """
    Save new IMSI code to file.
    """

    if CheckFile(Path, CodeFile) == False:
        logging.error('IMSI file not found; creating new %s file' % ConfigFile)

        f = open(Path + CodeFile, 'w')
        f.writelines(Code)
        f.close()

        logging.info('new IMSI code (%s) saved to file' % Code)        

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

def GetCode(CodeType):
    """
    Get current SIM IMSI code or device hardware IMEI code.
    """

    if CodeType == 'IMEI':
        Command = 'dbus-send --system --type=method_call --print-reply --dest=com.nokia.phone.SIM /com/nokia/phone/SIM/security Phone.Sim.Security.get_imei'
    elif CodeType == 'IMSI':
        Command = 'dbus-send --system --type=method_call --print-reply --dest=com.nokia.phone.SIM /com/nokia/phone/SIM Phone.Sim.get_imsi'

    try:
        Output = os.popen(Command).read()
        E = re.compile('string "(\S+)"')
        R = E.findall(Output)[0]
    except:
        logging.error("couldn't get %s code" % CodeType)
        return None
               
    return R

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

def GetOperatorName():
    """
    Get current SIM telecom operator name.
    """

    try:
        Output = os.popen('dbus-send --system --print-reply=literal --dest=com.nokia.phone.net /com/nokia/phone/net Phone.Net.get_registration_status').read()
        E = re.compile('uint32 (\d+)')
        R = E.findall(Output)
        Output = os.popen( 'dbus-send --system --print-reply --dest=com.nokia.phone.net /com/nokia/phone/net Phone.Net.get_operator_name byte:0 uint32:"%s" uint32:"%s"' % (R[1], R[2]) ).read()
        E = re.compile('string "(.*)"')
        R = E.findall(Output)[0]
    except:
        logging.error("couldn't get operator name")
        return 'UNKNOWN'        

    return R

############################################################################################################################
#   arguments
############################################################################################################################

def CheckArguments():
    """
    Check arguments for smscon_daemon.
    """    

    # check for arguments
    if sys.argv[1:] != []:
        NumArgs = len(sys.argv[1:])

        if NumArgs == 2:
            Mode = sys.argv[1]
            
            if Mode == '-test':
                Func = sys.argv[2]
                
                if Func == 'gps1' or Func == 'gps2': # test mode 1 & 2 for gps
                    StoreCurrentNetwork()
                    EnableConnection('GPRS')
                    #EnableConnectBehaviour('GPRS')
                    
                    if Func == 'gps1':
                        EnableGPStracking('single')
                    elif Func == 'gps2':
                        EnableGPStracking('multi')

                elif Func == 'ssh': # test mode for ssh connection
                    if StatusSSH() == True:
                        StopSSH(False)

                    StoreCurrentNetwork()
                    EnableConnection('GPRS')
                    #EnableConnectBehaviour('GPRS')
                    EnableSSHcontrol()

                elif Func == 'cam': # test mode for camera
                    StoreCurrentNetwork()
                    EnableConnection('GPRS')
                    #EnableConnectBehaviour('GPRS')
                    EnableCamera()
                    
                elif Func == 'sms': # test mode for sms
                    SMSsend(SENDERNUMBER, 'Test SMS from Nokia N900 device')
                    logging.info('send test SMS message to "%s"' % SENDERNUMBER)

                elif Func == 'email1' or Func == 'email2' : # test mode 1 & 2 for email
                    StoreCurrentNetwork()
                    EnableConnection('GPRS')
                    #EnableConnectBehaviour('GPRS')
                    
                    if Func == 'email1':
                        EMAILsend(EMAILADDRESS,
                                  'Test email from Nokia N900 device',
                                  'Email sending from Nokia N900 device is successfull.')
                    elif Func == 'email2':
                        if TakeCamPicture() == True:
                            EMAILsend(EMAILADDRESS,
                                      'Test email from Nokia N900 device',
                                      'This is a frontcam picture from Nokia N900 device:',
                                      LogPath + PhotoName)

                elif Func == 'call': # test mode for phone call
                    EnablePhonecall()

                else:
                    logging.error('test option error (%s)' % Func)
                    ExitDaemon()

            else:
                logging.error('test option error (%s)' % Mode)
                ExitDaemon()                

############################################################################################################################
#   autoloader
############################################################################################################################

def CheckAutoloader():
    """
    Check if smscon autoloads at system boot.
    """

    if CheckFile(BootPath, BootFile) == True:
        logging.info('smscon auto-loads at boot')
    else:
        logging.warning("smscon doesn't load at boot")

############################################################################################################################
#   keyboard detect (dbus)
############################################################################################################################

def KEYBOARDslider(Action, Type):
    """
    Check state change of keyboard slider.
    """

    if SMSCONactive == True:

        # keyboard slider: 'open to closed' state or 'closed to open' state
        KeyState = os.popen('cat /sys/devices/platform/gpio-switch/slide/state').read().strip('\n')

        if KeyState == 'closed' or KeyState == 'open':
            if EnableKeyboardDetect == True:
                #logging.debug(' Keyboard is used (%s) / (%s)' % (KeyState, EnableKeyboardDetect) )
                SMSsend(SenderNumber,
                        'NOKIA N900\n' + \
                        '%s\n' % GetTime() + \
                        '-Keyboard-\n' + \
                        'Phone is being used:\n' + \
                        'keyboard is %s.' % KeyState)           

                logging.info('send keyboard used sms to "%s"' % SenderNumber)

############################################################################################################################
#   check file
############################################################################################################################

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

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

############################################################################################################################
#   exit smscon_daemon
############################################################################################################################

def ExitDaemon():
    """
    Exit smscon_daemon.
    """

    RestorePreviousNetwork() # re-enable stored data network
    #logging.debug('InitialConnectBehaviour = [%s]' % InitialConnectBehaviour)
    #if InitialConnectBehaviour != None:
    #    EnableConnectBehaviour(InitialConnectBehaviour) # re-enable stored "Internet connection" behaviour

    logging.info('%s has stopped' % DaemonFile)
    sys.exit(1)

############################################################################################################################
#    MAIN
############################################################################################################################

# load user settings from smscon_config file
if CheckFile(Path, ConfigFile) == True:
    f = open(Path + ConfigFile, 'r')

    ConfigLines = f.readlines() 
    if ConfigLines == []:
        logging.critical('%s is empty.' % ConfigFile)
        ExitDaemon()
    else:
        try:
            for Line in ConfigLines:
                Line = Line.strip().replace('\r', '').replace('\n', '')
                
                for Var in ConfigVars:
                    # get user variable & it's value from text line
                    if Line.startswith('%s' % Var):
                        try:
                            Variable, Value = Line.split('=')
                        except:
                            logging.critical( 'syntax error in "%s" file (%s)' % (ConfigFile, Line) )
                            ExitDaemon()
                        else:
                            Value = Value.lstrip(' ')
                            try:
                                if Value.startswith("'") == True and Value.endswith("'") == True:
                                    vars()[Var] = Value.strip("'") # get string
                                else:
                                    vars()[Var] = int(Value) # get integer
                            except:
                                logging.critical( 'syntax error in "%s" file (%s)' % (ConfigFile, Line) )
                                ExitDaemon()
        except:
            logging.critical('error reading "%s" file' % ConfigFile)
            sys.exit(1)
        else:
            logging.info('successfully loaded "%s" file' % ConfigFile)

            # set reply sms number
            SenderNumber = SENDERNUMBER
            
            ShowSMScommands('log')
    f.close()

else:
    logging.warning("%s doesn't excist" % ConfigFile)
    ExitDaemon()

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

ValidateIMSI()
CheckAutoloader()

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

try:            
    DBusGMainLoop(set_as_default = True)

    bus = dbus.SystemBus()

    # set battery charge measurment
    hal_obj = bus.get_object('org.freedesktop.Hal',
                             '/org/freedesktop/Hal/Manager')

    hal = dbus.Interface(hal_obj,
                         'org.freedesktop.Hal.Manager')

    uids = hal.FindDeviceByCapability('battery')
    dev_obj = bus.get_object('org.freedesktop.Hal',
                             uids[0])

    # set GPS device control
    GpsControl = location.GPSDControl.get_default()
    GpsDevice  = location.GPSDevice()

    # set GPS method & interval
    if   GPSINTERVAL == '10':
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_10S)
    elif GPSINTERVAL == '20':
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_20S)
    elif GPSINTERVAL == '30':
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_30S)
    elif GPSINTERVAL == '60':
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_60S)
    elif GPSINTERVAL == '120':
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_120S)
    else:
        GpsControl.set_properties(preferred_method   = location.METHOD_GNSS|location.METHOD_AGNSS,
                                  preferred_interval = location.INTERVAL_60S)       
     
    GpsControl.connect( 'error-verbose', GPSerror, gobject.MainLoop() )
    GpsDevice.connect('changed', GPSchanged, GpsControl)
    GpsControl.connect( 'gpsd-stopped', GPSstop, gobject.MainLoop() )

    # set SMS signal receiver
    bus.add_signal_receiver(SMSreceive,
                            path           = '/com/nokia/phone/SMS',
                            dbus_interface = 'Phone.SMS',
                            signal_name    = 'IncomingSegment')

    # set keyboard slider signal receiver
    bus.add_signal_receiver(KEYBOARDslider,
                            path           = '/org/freedesktop/Hal/devices/platform_slide',
                            dbus_interface = 'org.freedesktop.Hal.Device',
                            signal_name    = 'Condition')

    CheckArguments()

    gobject.MainLoop().run()

except Exception, e:
    
    logging.critical('<<< SMSCON FATAL ERROR:\n%s >>>' % e)
    print 'SMSCON FATAL ERROR:\n%s' % e
    
    ExitDaemon()

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


"""
 0.4.4-5
 NEW: COM_CHECK returns all valid SMS commands
 NEW: improved email smtp server handling
 FIX: ssh connection passfrase for auth. keys added
 FIX: "Internet connection" behavior set to initial setting when smscon_daemon stops.
 FIX: email sending works with or without secure authentication (tested with Google gmail)

 0.4.4-4
 FIX: COM_REBOOT & COM_POWEROFF fails if changed.
 FIX: EnablePhoneCall() fails in test.

 0.4.4-3
 FIX: always enable GPRS connection before using GPS.
 FIX: METHOD_AGNSS to GNSS bug.
 FIX: Trackon / Trackoff works now.
 FIX: sms command can use spaces now.
 FIX: smscon_boot loads at device boot.
 NEW: keyboard detect function.
 FIX: when GPS is active all other program events are on hold/discarted.
"""






"""
from QtMobility.Messaging import *
from PySide.QtCore import *
from PyQt4 import QtCore
 
# define message to be sent
Num = QMessageAddress( QMessageAddress.Phone, QtCore.QString(Number) )
Msg = QMessage()
Msg.setType(QMessage.Sms)
Msg.setTo(Num)
Msg.setBody(Message)
 
# send message
sender = QMessageService()
if (sender.send(Msg)):
  print "email successfully send"
else:
  print "failed to send email"
"""
