#!/usr/bin/python
#-*- coding: utf-8 -*-

# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import socket
import sys, pwd, os
import random, string, datetime
import subprocess
from calculate.console.application.cert_func import owner, getRunProc

reload(sys)
sys.setdefaultencoding("utf-8")

from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('calculate_console',sys.modules[__name__])

def parse():
    import argparse
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument('-h', '--help', action='store_true', default=False,
                        dest='help',help=_("show this help message and exit"))
    parser.add_argument('--stop', action='store_true', default=False,
                        dest='stop', help=_("stop cl-consoled"))
    parser.add_argument('--restart', action='store_true', default=False,
                        dest='restart', help=_("restart cl-consoled"))
    return parser

def start():
    host = ''    # ip
    port = 5001  # порт
    backlog = 32  # ожидаемое количество ожидающих обработки запросов
    size = 1024  # размер данных
    # создаём сокет для IPv4
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # ассоциировать адрес с сокетом
    while True:
        try:
            s.bind((host,port))
            break
        except socket.error:
            port += 1

    home_path = pwd.getpwuid(os.getuid()).pw_dir
    file_path = os.path.join(home_path, '.calculate', 'passwd_daemon')

    # принимать запросы на установление соединения
    s.listen(backlog)

    passwd_list = []

    error_num = 0
    print 'password daemon start'
    time_last = datetime.datetime.now()
    find_flag = False
    while 1:
        char_list = [random.choice(string.letters) for x in xrange(128)]
        hash_val = "".join(char_list)

        fd = open(file_path, 'w')
        fd.write("%d %s" %(port, hash_val))
        fd.close()
        os.chmod(file_path, 0600)

        if error_num:
            return 1
        # принять запрос и преобразовать в соединение.
        # client - новое соединение
        try:
            client, address = s.accept()
        except KeyboardInterrupt:
            print
            return 1
        print "server: got connection from %s port %d" \
                                           %(address[0], address[1])
        
        # получаем данные от клиента с размером size=1024
        data = client.recv(size)
        time_now = datetime.datetime.now()
        if (time_now - time_last).seconds > 1200:
            client.send('Error: timeout')
            client.close()
            return 408
        else:
            time_last = time_now
        while len(data) > 0:
            if len(data.split(',')) == 4:
                s_host, s_port, username, userhash = data.split(',')

                if hash_val != userhash:
                    error_msg = 'Error: incorrect hash'
                    print error_msg
                    client.send(error_msg)
                    error_num += 1
                    break
                for password_dict in passwd_list:
                    if s_host == password_dict['host'] and \
                                s_port == password_dict['port'] and \
                                username == password_dict['username']:
                        #print 'FIND PASSWORD!!!'
                        client.send(password_dict['password'])
                        find_flag = True
                        data = ''
                        break
                if find_flag:
                    find_flag = False
                    break
                error_msg = 'Error: password not found'
                print error_msg
                client.send(error_msg)
                msg = client.recv(size)

                if len(msg.split(',')) == 5:
                    r_host,r_port,username,userhash,password = msg.split(',')
                    if hash_val != userhash:
                        client.send('Error: incorrect hash')
                        data = ''
                        error_num += 1
                        break
                    if r_host != s_host or r_port != s_port:
                        error_msg = 'Error: mismatch destination hosts'
                        print error_msg
                        client.send(error_msg)
                        data = ''
                        break
                    password_dict = {'host': r_host, 'port':r_port,
                                     'username':username, 'userhash':userhash,
                                     'password':password}
                    passwd_list.append(password_dict)
                    client.send('ok')
                    data = ''
                    break
            elif len(data.split(',')) == 5 and data.split(',')[0] == 'delete':
                delete, s_host, s_port, username, userhash = data.split(',')
                if hash_val != userhash:
                    error_msg = 'Error: incorrect hash'
                    print error_msg
                    client.send(error_msg)
                    error_num += 1
                    break
                for password_dict in passwd_list:
                    if s_host == password_dict['host'] and \
                                s_port == password_dict['port'] and \
                                username == password_dict['username']:
                        passwd_list.remove(password_dict)
                        data = ''
                        break
                data = ''
                break
            else:
                error_msg = 'Error: incorrect data'
                print error_msg
                client.send(error_msg)
                error_num += 1
                break
        client.close() # Закрыть соединение с клиентом
    return 0

def stop():
    username = pwd.getpwuid(os.getuid()).pw_name

    for run_commands in filter(lambda x:'cl-consoled' in \
                                        x[0],getRunProc()):
        if 'python' in run_commands[0]:
            if username == owner(run_commands[1]) and \
                        str(os.getpid()) != run_commands[1]:
                os.system('kill %s' %run_commands[1])

if __name__=='__main__':
    parser = parse()
    args = parser.parse_args()
    if args.stop or args.restart:
        stop()
    if not args.stop:
        while True:
            print 'start'
            res = start()
            if res != 408:
                sys.exit(res)
