#include "kylin_phone.h"

int init_status = -1;
void *handle_libphone_plugin_so = NULL;
PhonePluginInterface *phone_plugin_interface;

int phonectl_init()
{
  char *error = NULL;

  syslog(LOG_INFO, "加载动态库初始化\n");
  
  handle_libphone_plugin_so = dlopen(LIBPHONE_PLUGIN_SO, RTLD_LAZY);
  if (!handle_libphone_plugin_so) {
    syslog(LOG_INFO, "dlopen error:%s\n", dlerror());
    return -1;
  }

  // dlerror();

  phone_plugin_interface = dlsym(handle_libphone_plugin_so, "phone_plugin_interface");
  if (NULL != (error = dlerror())) {
    return -1;
  }

  // dlerror();

  syslog(LOG_INFO, "加载动态库完成\n");

  return 0;
}

int phonectl_uninit()
{
  if (init_status == 0 && NULL != handle_libphone_plugin_so) {
    dlclose(handle_libphone_plugin_so);
  }

  return 0;
}

void kylin_device_control_init()
{
  init_status = phonectl_init();
}

void kylin_device_control_fini()
{
  phonectl_uninit();
}

unsigned int phonectl_dev_control(const char *pid, const char *vid, const char *serial)
{
  /**
   * 管控状态：0禁用、1启用、2只读
   **/
  
  unsigned int status = 999;

  if (0 == init_status && NULL != phone_plugin_interface) {
      struct kdk_phone_dev dev;
      memset(&dev, 0x00, sizeof(dev));
      snprintf((char*)dev.pid, sizeof(dev.pid), "%s", pid);
      snprintf((char*)dev.vid, sizeof(dev.vid), "%s", vid);
      snprintf((char*)dev.serial, sizeof(dev.serial), "%s", serial);
      status = phone_plugin_interface->phone_dev_control(&dev);
  }

  return status;
}

int get_process_path_by_pid(char *path, const pid_t pid, size_t len)
{
  int size = 0, byte = 0;
  char proc_path[1024] = {0}, link_path[1024] = {0};
  
  if (!path || pid <= 0 || len < 1024) {
    return -1;
  }

  memset(proc_path, 0x00, sizeof(proc_path));
  size = snprintf(proc_path, sizeof(proc_path), "/proc/%d/exe", pid);
  if (size < 0) {
    return -1;
  }

  memset(link_path, 0x00, sizeof(link_path));
  byte = readlink(proc_path, link_path, sizeof(link_path));
  if (byte < 0) {
    return -1;
  }

  snprintf(path, len, "%s", link_path);

  return 0;
}

unsigned int phonectl_dev_file_control(const pid_t process_id, const char *pid, const char *vid, const char *serial)
{
  /**
   * 管控状态：0禁用、1启用
   **/
  
  unsigned int status = 1;
  char process_name[1024] = {0};

  if (0 == init_status && NULL != phone_plugin_interface) {

    memset(process_name, 0x00, sizeof(process_name));
    int ret = get_process_path_by_pid(process_name, process_id, sizeof(process_name));
    if (ret != 0) {
      syslog(LOG_INFO, "[文件外发管控] 进程ID：%d，获取进程信息失败", process_id);
      return 0;
    }

    struct kdk_phone_dev dev;
    memset(&dev, 0x00, sizeof(dev));
    snprintf((char*)dev.pid, sizeof(dev.pid), "%s", pid);
    snprintf((char*)dev.vid, sizeof(dev.vid), "%s", vid);
    snprintf((char*)dev.serial, sizeof(dev.serial), "%s", serial);
    status = phone_plugin_interface->phone_dev_file_control(process_name, &dev);
  }

  return status;
}

int kysec_devctl_set_adb_status_api(int status)
{
    void *handle = NULL;
    int (*check)(int);
    char *error;
    int retval = 0;

    handle = dlopen("libkysec_extend.so.0", RTLD_LAZY);

    if (!handle)
    {
        syslog(LOG_INFO,"Failed to open libkysec_extend - %s", dlerror());
        return 1;
    }

    dlerror();
    check = (int (*)(int))dlsym(handle, "kysec_devctl_set_adb_status");
    error = dlerror();
    if (error)
    {
        syslog(LOG_INFO,"Failed to obtain address of symbol - %s", error);
        dlclose(handle);
        return 1;
    }

    retval = (*check)(status);
    dlclose(handle);
    return retval;
}

static void gettime(char *output, size_t output_size)//获取时间
{
    struct timeval tv;
    gettimeofday(&tv,NULL);//获取1970-1-1到现在的时间结果保存到tv中
    struct tm cur_tm;//保存转换后的时间结果
    localtime_r((time_t*)&tv.tv_sec,&cur_tm);
    snprintf(output,output_size,"%d-%02d-%02d %02d:%02d:%02d",cur_tm.tm_year+1900,cur_tm.tm_mon+1,cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min,cur_tm.tm_sec);
}

static char* getusername()//获取用户名
{
    struct passwd *pwd = getpwuid(getuid());
    printf("login account：%s\n", pwd->pw_name);
    return pwd->pw_name;
}

char *getip()//获取ip
{
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char *host = NULL;

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        return NULL;
    }

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        if (!strcmp(ifa->ifa_name, "lo"))
            continue;
        if (family == AF_INET) {
            if ((host = malloc(NI_MAXHOST)) == NULL)
                return NULL;
            s = getnameinfo(ifa->ifa_addr,
                            (family == AF_INET) ? sizeof(struct sockaddr_in) :
                            sizeof(struct sockaddr_in6),
                            host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
            if (s != 0) {
                return NULL;
            }
            freeifaddrs(ifaddr);
            return host;
        }
    }
    return " ";
}

void send_log(GDBusProxy *proxy,char xx[])
{
    GVariant *result;
    GError *error = NULL;
    printf("...\n");
    result = g_dbus_proxy_call_sync(proxy,
                                    "log_transmit",
                                    g_variant_new ("(s)", xx),
                                    G_DBUS_CALL_FLAGS_NONE,
                                    -1,
                                    NULL,
                                    &error);
//    g_assert_no_error(error);
    g_variant_unref(result);
}


int pass_by_dbus(char xx[])
{
    GDBusProxy *proxy;
    GDBusConnection *conn;
    GError *error = NULL;


    conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
    g_assert_no_error(error);

    proxy = g_dbus_proxy_new_sync(conn,
                                  G_DBUS_PROXY_FLAGS_NONE,
                                  NULL,				/* GDBusInterfaceInfo */
                                  "org.log.sys_transmit",		/* name */
                                  "/org/log/sys_transmit",	/* object path */
                                  "org.log.transmit",	/* interface */
                                  NULL,				/* GCancellable */
                                  &error);
    g_assert_no_error(error);

    send_log(proxy,xx);
    syslog(LOG_INFO,"send to log_transmit %s", xx);

    g_object_unref(proxy);
    g_object_unref(conn);
    return 0;
}

static int message_add(char *message, size_t *message_size, const char *key, const char *value)
{
    if(key == NULL){
      syslog(LOG_ERR,"message's key can not be null");
    	return -1;
    }

    if(value == NULL){
      syslog(LOG_WARNING,"the value of message's key %s is null", key);
      value = "none";
    }

    if (*message_size + strlen(key) + strlen(value) + SEPARATOR_LEN > MESSAGE_MAX_LEN) {
        // 超出缓冲区大小，返回错误
        return -1;
    }

    if (*message_size > 0) {
        // 如果不是第一个键值对，添加逗号
        strcat(message, ",");
        (*message_size)++;
    }

    // 添加键值对
    strcat(message, "\\\"");
    strcat(message, key);
    strcat(message, "\\\":\\\"");
    strcat(message, value);
    strcat(message, "\\\"");
    *message_size += strlen(key) + strlen(value) + SEPARATOR_LEN;

    return 0;
}

void send_message(const char *module_name, const char *log_level, const char *device_status, const PhoneInfo *device_info, const char *action, const char *device_control)
{
    char buf[BUF_MAX_LEN+MESSAGE_MAX_LEN]={0};
    char message[MESSAGE_MAX_LEN] = {0};
    size_t message_size = 0;

  if (device_info == NULL)
  {
    syslog(LOG_WARNING, "device_info is null");
    return;
  }

  char k_time[40];
  gettime(k_time,40);

  // 获取用户名
  const char *username = getusername();
  if (username == NULL) {
    username = "none";
  }

  // 获取主机名
  char host_name[126]={0};
  int result = gethostname(host_name, sizeof(host_name));
  if (result)
  {
    // 设置默认主机名
    strcpy(host_name, "none");
  }

  // 获取IP地址
  const char *ip = getip();
  if (ip == NULL) {
    ip = "none";
  }

    // 构建 message
    char info[126]={0};
    snprintf(info,sizeof(info)-1,"PID:%s,VID:%s",device_info->pid,device_info->vid);

    char name[126]={0};
    snprintf(name,sizeof(name)-1,"%s %s",device_info->vendor,device_info->model);
    message_add(message, &message_size, "host_name", host_name);
    message_add(message, &message_size, "user_name", username);
    message_add(message, &message_size, "device_type", "phone");
    message_add(message, &message_size, "action", action);
    message_add(message, &message_size, "device_info", info);
    message_add(message, &message_size, "device_control", device_control);
    message_add(message, &message_size, "device_name", name);
    message_add(message, &message_size, "device_path", device_info->path );
    message_add(message, &message_size, "device_status", device_status);
    message_add(message, &message_size, "device_pid", device_info->pid );
    message_add(message, &message_size, "device_vid", device_info->vid );
    message_add(message, &message_size, "device_serial", device_info->serial );
    message_add(message, &message_size, "device_manufacturer", device_info->vendor );
    message_add(message, &message_size, "device_product", device_info->model);
    message[message_size] = '\0';

  // 构建 buf
  snprintf(buf, sizeof(buf)-1,"{\"time\":\"%s\",\"hostname\":\"%s\",\"name\":\"%s\",\"ip\":\"%s\",\"lv\":\"%s\",\"message\":\"{%s}\"}",
          k_time,
          username,
          module_name,
          ip,
          log_level,
          message);

  pass_by_dbus(buf);
}

void kysec_security_free(PhoneInfo *info){

 if(info != NULL){
        if(info->path)   g_free(info->path);
        if(info->model)  g_free(info->model);
        if(info->pid)    g_free(info->pid);
        if(info->vendor) g_free(info->vendor);
        if(info->vid)    g_free(info->vid);
        if(info->serial) g_free(info->serial);
        if(info)         free(info);

        info = NULL;
  }
}
