/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
**/
#include <QCoreApplication>

#include <glib.h>
#include "run-passwd.h"

/*using pam change password*/
#include <stdio.h>
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <string.h>

static const char *non_interactive_password = "";
static const char *new_password = "";
static int isCurrentPwd = 0;
static char *error = "";

static int changeCurrent_conv (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
    struct pam_response *responses;
    int count;

//    assert (NULL != non_interactive_password);

    if (num_msg <= 0 || num_msg >= PAM_MAX_NUM_MSG) {
        printf("bad number of messages %d <= 0 || >= %d\n", num_msg, PAM_MAX_NUM_MSG);
        *resp = NULL;
        return PAM_CONV_ERR;
    }

    responses = (struct pam_response *) calloc ((size_t) num_msg, sizeof (*responses));
    if (NULL == responses) {
        return PAM_BUF_ERR;
    }

    //循环每个消息
    for (count=0; count < num_msg; count++) {
        //初始化响应变量
        responses[count].resp_retcode = 0;

//        printf("message[%d]: %d %s\n", count, msg[count]->msg_style, msg[count]->msg);

        //根据消息类型处理消息
        switch (msg[count]->msg_style) {

        //回显消息，从标准输入获取数据并显示在屏幕上，一般是交互的名称信息，如用户名等
        case PAM_PROMPT_ECHO_ON:
            fprintf (stderr, "PAM modules requesting echoing are not supported.\n");
            goto failed_conversation;

        //从标准输入获取不回显数据，一般是输入密码
        case PAM_PROMPT_ECHO_OFF:
            if (isCurrentPwd == 0){
                isCurrentPwd = 1;
                responses[count].resp = strdup (non_interactive_password);
            } else {
                responses[count].resp = strdup (new_password);
            }

            if (NULL == responses[count].resp) {
                goto failed_conversation;
            }
            break;

        //回显PAM模块传递的错误消息
        case PAM_ERROR_MSG:
            if ((NULL == msg[count]->msg)) {
                goto failed_conversation;
            } else {
                error = strdup(msg[count]->msg);
            }
            responses[count].resp = NULL;
            break;

        //回显PAM模块传递的文本消息
        case PAM_TEXT_INFO:
            if ((NULL == msg[count]->msg)) {
                goto failed_conversation;
            } else {
                error = strdup(msg[count]->msg);
            }
            responses[count].resp = NULL;
            break;

        default:
            (void) fprintf (stderr, ("conversation type %d not supported.\n"), msg[count]->msg_style);
            goto failed_conversation;
        }
    }

    *resp = responses;

    return PAM_SUCCESS;

failed_conversation:
    for (count=0; count < num_msg; count++) {
        if (NULL != responses[count].resp) {
            memset (responses[count].resp, 0, strlen (responses[count].resp));
            free (responses[count].resp);
            responses[count].resp = NULL;
        }
    }

    free (responses);
    *resp = NULL;

    return PAM_CONV_ERR;
}

int main(int argc, char *argv[])
{
    struct pam_conv conv;
    int ret = 0;
    pam_handle_t * pamh = NULL;
    const char *username = g_get_user_name();
    if (argc == 3) {
        non_interactive_password = argv[1];
        new_password = argv[2];
    } else {
        printf("missing parameter!\n");
        return -1;
    }

    //会话函数传递到PAM模块中，在模块中通过pam_get_item获取并调用
    conv.conv = changeCurrent_conv;
    conv.appdata_ptr = NULL;

    //
    if ((pam_start("passwd", username, &conv, &pamh)) != PAM_SUCCESS){
        return 0;
    }

    //
    ret = pam_chauthtok(pamh, 0);
    if (ret == PAM_SUCCESS){
        if (error != "") {
            printf("%s\n", error);
            free(error);
        }
    } else {
        if (error == "") {
            printf("Unable to modify password!\n");
        } else {
            printf("%s\n", error);
            free(error);
        }
    }

    //结束PAM
    ret = pam_end(pamh, ret);

    return ret;
}

/*end pam*/


PasswdHandler *passwd_handler = NULL;

static void auth_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);
static void chpasswd_cb (PasswdHandler *passwd_handler, GError *error, gpointer user_data);

//int main(int argc, char *argv[])
//{

//    if (argc != 3)
//    {
//        return -1;
//    }

//    QCoreApplication a(argc, argv);

//    passwd_handler = passwd_init ();

//    passwd_authenticate (passwd_handler, argv[1], auth_cb, argv[2]);

//    return a.exec();
//}

static void
auth_cb (PasswdHandler *passwd_handler,
         GError        *error,
         gpointer       user_data)
{
    char *secondary_text;
    char * pwd = (char*) user_data;

    if (error){
        secondary_text = error->message;
        char ** lines = g_strsplit(secondary_text, "\n", -1);
        printf("%s\n", lines[0]);
        qApp->exit(1);
    } else {
        passwd_change_password (passwd_handler, pwd, chpasswd_cb, NULL);
    }

}

/**
 * @brief chpasswd_cb
 * @param passwd_handler
 * @param error
 * @param user_data
 */
static void
chpasswd_cb (PasswdHandler *passwd_handler,
             GError        *error,
             gpointer       user_data)
{
//    char *primary_text;
    char *secondary_text;

    if (!error) {
        //finish_password_change (TRUE);
//        primary_text = "Success";
        secondary_text = "";

        printf("%s\n", secondary_text);

        qApp->exit(0);
    } else {
//        primary_text = "Failed";
        secondary_text = error->message;

        char ** lines = g_strsplit(secondary_text, "\n", -1);

        printf("%s\n", lines[0]);

        passwd_destroy (passwd_handler);

        qApp->exit(1);
    }

}
